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

   The MIT License

   Copyright (c) 2008 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    SBVRGeogen3D.cpp
  \author  Jens Krueger
           SCI Institute
           University of Utah
  \date    September 2008
*/

#include "StdTuvokDefines.h"
#include <algorithm>
#include <cassert>
#include <cmath>
#include <functional>
#include <limits>
#include "SBVRGeogen3D.h"
#include "MathTools.h"

using namespace tuvok;

static bool CheckOrdering(const FLOATVECTOR3& a, const FLOATVECTOR3& b,
                          const FLOATVECTOR3& c);
static void SortPoints(std::vector<VERTEX_FORMAT> &fArray);

SBVRGeogen3D::SBVRGeogen3D(void) :
  SBVRGeogen(),
  m_fMaxZ(0),
  m_fMinZ(0)
{
}

SBVRGeogen3D::~SBVRGeogen3D(void)
{
}

// Finds the point with the minimum position in Z.
struct vertex_max_z : public std::binary_function<VERTEX_FORMAT,
                                                  VERTEX_FORMAT,
                                                  bool> {
  bool operator()(const VERTEX_FORMAT &a, const VERTEX_FORMAT &b) const {
    return (a.m_vPos.z < b.m_vPos.z);
  }
};

// Finds the point with the maximum position in Z.
struct vertex_min_z : public std::binary_function<VERTEX_FORMAT,
  VERTEX_FORMAT,
  bool> {
    bool operator()(const VERTEX_FORMAT &a, const VERTEX_FORMAT &b) const {
      return (a.m_vPos.z > b.m_vPos.z);
    }
};

void SBVRGeogen3D::InitBBOX() {
  SBVRGeogen::InitBBOX();
  // find the maximum z value
  m_fMaxZ = (*std::max_element(m_pfBBOXVertex, m_pfBBOXVertex+8,
                                               vertex_max_z())).m_vPos.z;
  m_fMinZ = (*std::max_element(m_pfBBOXVertex, m_pfBBOXVertex+8,
    vertex_min_z())).m_vPos.z;

}

bool SBVRGeogen3D::DepthPlaneIntersection(float z,
                                const VERTEX_FORMAT &plA,
                                const VERTEX_FORMAT &plB,
                                std::vector<VERTEX_FORMAT>& vHits,
                                bool bClip)
{
  /*
     returns NO INTERSECTION if the line of the 2 points a,b is
     1. in front of the intersection plane
     2. behind the intersection plane
     3. parallel to the intersection plane (both points have
        "pretty much" the same z)
  */
  if ((z > plA.m_vPos.z && z > plB.m_vPos.z) ||
      (z < plA.m_vPos.z && z < plB.m_vPos.z) ||
      (EpsilonEqual(plA.m_vPos.z, plB.m_vPos.z))) {
    return false;
  }

  float fAlpha = (z - plA.m_vPos.z) /
                 (plA.m_vPos.z - plB.m_vPos.z);

  VERTEX_FORMAT vHit;

  vHit.m_vPos.x = plA.m_vPos.x + (plA.m_vPos.x - plB.m_vPos.x) * fAlpha;
  vHit.m_vPos.y = plA.m_vPos.y + (plA.m_vPos.y - plB.m_vPos.y) * fAlpha;
  vHit.m_vPos.z = z;

  vHit.m_vVertexData = plA.m_vVertexData + (plA.m_vVertexData - plB.m_vVertexData) * fAlpha;
  vHit.m_bClip = bClip;

  vHits.push_back(vHit);

  return true;
}

// Functor to identify the point with the lowest `y' coordinate.
struct vertex_min : public std::binary_function<VERTEX_FORMAT,
                                                VERTEX_FORMAT,
                                                bool> {
  bool operator()(const VERTEX_FORMAT &a, const VERTEX_FORMAT &b) const {
    return (a.m_vPos.y < b.m_vPos.y);
  }
};

// Sorts a vector
void SBVRGeogen3D::SortByGradient(std::vector<VERTEX_FORMAT>& fArray)
{
  // move bottom element to front of array
  if(fArray.empty()) { return; }
  std::swap(fArray[0],
            *std::min_element(fArray.begin(), fArray.end(), vertex_min()));
  if(fArray.size() > 2) {
    // sort points according to gradient
    SortPoints(fArray);
  }
}

void SBVRGeogen3D::Triangulate(std::vector<VERTEX_FORMAT> &fArray) {
  SortByGradient(fArray);

  // convert to triangles
  for (uint32_t i=0; i<(fArray.size()-2) ; i++) {
    m_vSliceTriangles.push_back(fArray[0]);
    m_vSliceTriangles.push_back(fArray[i+1]);
    m_vSliceTriangles.push_back(fArray[i+2]);
  }
}

bool SBVRGeogen3D::ComputeLayerGeometry(float fDepth) {
  std::vector<VERTEX_FORMAT> vLayerPoints;
  vLayerPoints.reserve(12);

  assert(!MathTools::NaN(fDepth));

  DepthPlaneIntersection(fDepth, m_pfBBOXVertex[0], m_pfBBOXVertex[1],
                      vLayerPoints, m_bClipVolume);
  DepthPlaneIntersection(fDepth, m_pfBBOXVertex[1], m_pfBBOXVertex[2],
                      vLayerPoints, m_bClipVolume);
  DepthPlaneIntersection(fDepth, m_pfBBOXVertex[2], m_pfBBOXVertex[3],
                      vLayerPoints, m_bClipVolume);
  DepthPlaneIntersection(fDepth, m_pfBBOXVertex[3], m_pfBBOXVertex[0],
                      vLayerPoints, m_bClipVolume);

  DepthPlaneIntersection(fDepth, m_pfBBOXVertex[4], m_pfBBOXVertex[5],
                      vLayerPoints, m_bClipVolume);
  DepthPlaneIntersection(fDepth, m_pfBBOXVertex[5], m_pfBBOXVertex[6],
                      vLayerPoints, m_bClipVolume);
  DepthPlaneIntersection(fDepth, m_pfBBOXVertex[6], m_pfBBOXVertex[7],
                      vLayerPoints, m_bClipVolume);
  DepthPlaneIntersection(fDepth, m_pfBBOXVertex[7], m_pfBBOXVertex[4],
                      vLayerPoints, m_bClipVolume);

  DepthPlaneIntersection(fDepth, m_pfBBOXVertex[4], m_pfBBOXVertex[0],
                      vLayerPoints, m_bClipVolume);
  DepthPlaneIntersection(fDepth, m_pfBBOXVertex[5], m_pfBBOXVertex[1],
                      vLayerPoints, m_bClipVolume);
  DepthPlaneIntersection(fDepth, m_pfBBOXVertex[6], m_pfBBOXVertex[2],
                      vLayerPoints, m_bClipVolume);
  DepthPlaneIntersection(fDepth, m_pfBBOXVertex[7], m_pfBBOXVertex[3],
                      vLayerPoints, m_bClipVolume);

  if (vLayerPoints.size() <= 2) {
    return false;
  }

  // insert mesh triangles
  if (HasMesh()) InsertMeshUpToSlice(fDepth);

  Triangulate(vLayerPoints);

  return true;
}

float SBVRGeogen3D::GetLayerDistance() const {
  return (0.5f * 1.0f/m_fSamplingModifier *
          (m_vAspect/FLOATVECTOR3(m_vSize))).minVal();
}

void SBVRGeogen3D::InsertMeshUpToSlice(float fDepth) {
  for (SortIndexPVec::const_iterator index = m_MeshTransferIter;
       index != m_mesh.end();
       index++) {
    if ((*index)->fDepth <= fDepth) {
      m_MeshTransferIter = index;
      return;
    }
    MeshEntryToVertexFormat(m_vSliceTriangles, (*index)->m_mesh, (*index)->m_index, m_bClipMesh);
  }
  m_MeshTransferIter = m_mesh.end();
}

void SBVRGeogen3D::DepthSortMeshWithVolume() {

  // this is m_matWorldView without the brick transformation
  FLOATMATRIX4 matWorldView = m_matWorld * m_matView;

  // change "depth" from "distance to eye z-depth
  for (SortIndexPVec::iterator index = m_mesh.begin();
       index != m_mesh.end();
       index++) {

    // get poly centroid
    FLOATVECTOR3 centroid = (*index)->m_centroid;

    // transform it
    centroid = (FLOATVECTOR4(centroid,1) * matWorldView).xyz();

    (*index)->fDepth = centroid.z;
  }
  // sort
  std::sort(m_mesh.begin(), m_mesh.end(), DistanceSortOver);
  m_MeshTransferIter = m_mesh.begin();
}

void SBVRGeogen3D::ComputeGeometry(bool bMeshOnly) {
  InitBBOX();

  m_vSliceTriangles.clear();

  if (bMeshOnly)  {
    SortMeshWithoutVolume(m_vSliceTriangles);
    return;
  }

  float fDepth = m_fMaxZ;
  float fLayerDistance = GetLayerDistance();

  // I hit this every time I fiddle with the integration of an
  // application.  If an app doesn't set brick metadata properly, we'll
  // calculate a bad minimum Z value of nan. nan + anything is still nan,
  // so we end up with an infinite loop computing geometry below.
  assert(!MathTools::NaN(fDepth));

  // prepare mesh triangles for insertion (i.e. sort them)
  if (HasMesh()) DepthSortMeshWithVolume();

  do {
    ComputeLayerGeometry(fDepth);
    fDepth -= fLayerDistance;
  } while (fDepth > m_fMinZ);

  // insert all the leftover triangles they must be behind the last plane
  if (HasMesh()) {
    for (SortIndexPVec::const_iterator index = m_MeshTransferIter;
         index != m_mesh.end();
         index++) {
      MeshEntryToVertexFormat(m_vSliceTriangles, (*index)->m_mesh, (*index)->m_index, m_bClipMesh);
    }
  }

  if(m_bClipPlaneEnabled && (m_bClipVolume || m_bClipMesh)) {
    PLANE<float> transformed = m_ClipPlane * m_matView;
    const FLOATVECTOR3 normal(transformed.xyz());
    const float d = transformed.d();
    m_vSliceTriangles = ClipTriangles(m_vSliceTriangles, normal, d);
  }

}

// Checks the ordering of two points relative to a third.
static bool CheckOrdering(const FLOATVECTOR3& a,
                          const FLOATVECTOR3& b,
                          const FLOATVECTOR3& c) {
  float g1 = (a.y-c.y)/(a.x-c.x),
        g2 = (b.y-c.y)/(b.x-c.x);

  if (EpsilonEqual(a.x,c.x))
    return (g2 < 0) || (EpsilonEqual(g2,0.0f) && b.x < c.x);
  if (EpsilonEqual(b.x,c.x))
    return (g1 > 0) || (EpsilonEqual(g1,0.0f) && a.x > c.x);

  if (a.x < c.x)
    if (b.x < c.x) return g1 < g2; else return false;
  else
    if (b.x < c.x) return true; else return g1 < g2;
}

/// @todo: should be replaced with std::sort.
static void SortPoints(std::vector<VERTEX_FORMAT> &fArray) {
  // for small arrays, this bubble sort actually beats qsort.
  for (uint32_t i= 1;i<fArray.size();++i)
    for (uint32_t j = 1;j<fArray.size()-i;++j)
      if (!CheckOrdering(fArray[j].m_vPos,fArray[j+1].m_vPos,fArray[0].m_vPos))
        std::swap(fArray[j], fArray[j+1]);
}
<commit_msg>Ensure we make progress.<commit_after>/*
   For more information, please see: http://software.sci.utah.edu

   The MIT License

   Copyright (c) 2008 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    SBVRGeogen3D.cpp
  \author  Jens Krueger
           SCI Institute
           University of Utah
  \date    September 2008
*/

#include "StdTuvokDefines.h"
#include <algorithm>
#include <cassert>
#include <cmath>
#include <functional>
#include <limits>
#include "SBVRGeogen3D.h"
#include "MathTools.h"

using namespace tuvok;

static bool CheckOrdering(const FLOATVECTOR3& a, const FLOATVECTOR3& b,
                          const FLOATVECTOR3& c);
static void SortPoints(std::vector<VERTEX_FORMAT> &fArray);

SBVRGeogen3D::SBVRGeogen3D(void) :
  SBVRGeogen(),
  m_fMaxZ(0),
  m_fMinZ(0)
{
}

SBVRGeogen3D::~SBVRGeogen3D(void)
{
}

// Finds the point with the minimum position in Z.
struct vertex_max_z : public std::binary_function<VERTEX_FORMAT,
                                                  VERTEX_FORMAT,
                                                  bool> {
  bool operator()(const VERTEX_FORMAT &a, const VERTEX_FORMAT &b) const {
    return (a.m_vPos.z < b.m_vPos.z);
  }
};

// Finds the point with the maximum position in Z.
struct vertex_min_z : public std::binary_function<VERTEX_FORMAT,
  VERTEX_FORMAT,
  bool> {
    bool operator()(const VERTEX_FORMAT &a, const VERTEX_FORMAT &b) const {
      return (a.m_vPos.z > b.m_vPos.z);
    }
};

void SBVRGeogen3D::InitBBOX() {
  SBVRGeogen::InitBBOX();
  // find the maximum z value
  m_fMaxZ = (*std::max_element(m_pfBBOXVertex, m_pfBBOXVertex+8,
                                               vertex_max_z())).m_vPos.z;
  m_fMinZ = (*std::max_element(m_pfBBOXVertex, m_pfBBOXVertex+8,
    vertex_min_z())).m_vPos.z;

}

bool SBVRGeogen3D::DepthPlaneIntersection(float z,
                                const VERTEX_FORMAT &plA,
                                const VERTEX_FORMAT &plB,
                                std::vector<VERTEX_FORMAT>& vHits,
                                bool bClip)
{
  /*
     returns NO INTERSECTION if the line of the 2 points a,b is
     1. in front of the intersection plane
     2. behind the intersection plane
     3. parallel to the intersection plane (both points have
        "pretty much" the same z)
  */
  if ((z > plA.m_vPos.z && z > plB.m_vPos.z) ||
      (z < plA.m_vPos.z && z < plB.m_vPos.z) ||
      (EpsilonEqual(plA.m_vPos.z, plB.m_vPos.z))) {
    return false;
  }

  float fAlpha = (z - plA.m_vPos.z) /
                 (plA.m_vPos.z - plB.m_vPos.z);

  VERTEX_FORMAT vHit;

  vHit.m_vPos.x = plA.m_vPos.x + (plA.m_vPos.x - plB.m_vPos.x) * fAlpha;
  vHit.m_vPos.y = plA.m_vPos.y + (plA.m_vPos.y - plB.m_vPos.y) * fAlpha;
  vHit.m_vPos.z = z;

  vHit.m_vVertexData = plA.m_vVertexData + (plA.m_vVertexData - plB.m_vVertexData) * fAlpha;
  vHit.m_bClip = bClip;

  vHits.push_back(vHit);

  return true;
}

// Functor to identify the point with the lowest `y' coordinate.
struct vertex_min : public std::binary_function<VERTEX_FORMAT,
                                                VERTEX_FORMAT,
                                                bool> {
  bool operator()(const VERTEX_FORMAT &a, const VERTEX_FORMAT &b) const {
    return (a.m_vPos.y < b.m_vPos.y);
  }
};

// Sorts a vector
void SBVRGeogen3D::SortByGradient(std::vector<VERTEX_FORMAT>& fArray)
{
  // move bottom element to front of array
  if(fArray.empty()) { return; }
  std::swap(fArray[0],
            *std::min_element(fArray.begin(), fArray.end(), vertex_min()));
  if(fArray.size() > 2) {
    // sort points according to gradient
    SortPoints(fArray);
  }
}

void SBVRGeogen3D::Triangulate(std::vector<VERTEX_FORMAT> &fArray) {
  SortByGradient(fArray);

  // convert to triangles
  for (uint32_t i=0; i<(fArray.size()-2) ; i++) {
    m_vSliceTriangles.push_back(fArray[0]);
    m_vSliceTriangles.push_back(fArray[i+1]);
    m_vSliceTriangles.push_back(fArray[i+2]);
  }
}

bool SBVRGeogen3D::ComputeLayerGeometry(float fDepth) {
  std::vector<VERTEX_FORMAT> vLayerPoints;
  vLayerPoints.reserve(12);

  assert(!MathTools::NaN(fDepth));

  DepthPlaneIntersection(fDepth, m_pfBBOXVertex[0], m_pfBBOXVertex[1],
                      vLayerPoints, m_bClipVolume);
  DepthPlaneIntersection(fDepth, m_pfBBOXVertex[1], m_pfBBOXVertex[2],
                      vLayerPoints, m_bClipVolume);
  DepthPlaneIntersection(fDepth, m_pfBBOXVertex[2], m_pfBBOXVertex[3],
                      vLayerPoints, m_bClipVolume);
  DepthPlaneIntersection(fDepth, m_pfBBOXVertex[3], m_pfBBOXVertex[0],
                      vLayerPoints, m_bClipVolume);

  DepthPlaneIntersection(fDepth, m_pfBBOXVertex[4], m_pfBBOXVertex[5],
                      vLayerPoints, m_bClipVolume);
  DepthPlaneIntersection(fDepth, m_pfBBOXVertex[5], m_pfBBOXVertex[6],
                      vLayerPoints, m_bClipVolume);
  DepthPlaneIntersection(fDepth, m_pfBBOXVertex[6], m_pfBBOXVertex[7],
                      vLayerPoints, m_bClipVolume);
  DepthPlaneIntersection(fDepth, m_pfBBOXVertex[7], m_pfBBOXVertex[4],
                      vLayerPoints, m_bClipVolume);

  DepthPlaneIntersection(fDepth, m_pfBBOXVertex[4], m_pfBBOXVertex[0],
                      vLayerPoints, m_bClipVolume);
  DepthPlaneIntersection(fDepth, m_pfBBOXVertex[5], m_pfBBOXVertex[1],
                      vLayerPoints, m_bClipVolume);
  DepthPlaneIntersection(fDepth, m_pfBBOXVertex[6], m_pfBBOXVertex[2],
                      vLayerPoints, m_bClipVolume);
  DepthPlaneIntersection(fDepth, m_pfBBOXVertex[7], m_pfBBOXVertex[3],
                      vLayerPoints, m_bClipVolume);

  if (vLayerPoints.size() <= 2) {
    return false;
  }

  // insert mesh triangles
  if (HasMesh()) InsertMeshUpToSlice(fDepth);

  Triangulate(vLayerPoints);

  return true;
}

float SBVRGeogen3D::GetLayerDistance() const {
  return (0.5f * 1.0f/m_fSamplingModifier *
          (m_vAspect/FLOATVECTOR3(m_vSize))).minVal();
}

void SBVRGeogen3D::InsertMeshUpToSlice(float fDepth) {
  for (SortIndexPVec::const_iterator index = m_MeshTransferIter;
       index != m_mesh.end();
       index++) {
    if ((*index)->fDepth <= fDepth) {
      m_MeshTransferIter = index;
      return;
    }
    MeshEntryToVertexFormat(m_vSliceTriangles, (*index)->m_mesh, (*index)->m_index, m_bClipMesh);
  }
  m_MeshTransferIter = m_mesh.end();
}

void SBVRGeogen3D::DepthSortMeshWithVolume() {

  // this is m_matWorldView without the brick transformation
  FLOATMATRIX4 matWorldView = m_matWorld * m_matView;

  // change "depth" from "distance to eye z-depth
  for (SortIndexPVec::iterator index = m_mesh.begin();
       index != m_mesh.end();
       index++) {

    // get poly centroid
    FLOATVECTOR3 centroid = (*index)->m_centroid;

    // transform it
    centroid = (FLOATVECTOR4(centroid,1) * matWorldView).xyz();

    (*index)->fDepth = centroid.z;
  }
  // sort
  std::sort(m_mesh.begin(), m_mesh.end(), DistanceSortOver);
  m_MeshTransferIter = m_mesh.begin();
}

void SBVRGeogen3D::ComputeGeometry(bool bMeshOnly) {
  InitBBOX();

  m_vSliceTriangles.clear();

  if (bMeshOnly)  {
    SortMeshWithoutVolume(m_vSliceTriangles);
    return;
  }

  float fDepth = m_fMaxZ;
  float fLayerDistance = GetLayerDistance();
  assert(fLayerDistance > 0);

  // I hit this every time I fiddle with the integration of an
  // application.  If an app doesn't set brick metadata properly, we'll
  // calculate a bad minimum Z value of nan. nan + anything is still nan,
  // so we end up with an infinite loop computing geometry below.
  assert(!MathTools::NaN(fDepth));

  // prepare mesh triangles for insertion (i.e. sort them)
  if (HasMesh()) DepthSortMeshWithVolume();

  do {
    ComputeLayerGeometry(fDepth);
    fDepth -= fLayerDistance;
  } while (fDepth > m_fMinZ);

  // insert all the leftover triangles they must be behind the last plane
  if (HasMesh()) {
    for (SortIndexPVec::const_iterator index = m_MeshTransferIter;
         index != m_mesh.end();
         index++) {
      MeshEntryToVertexFormat(m_vSliceTriangles, (*index)->m_mesh, (*index)->m_index, m_bClipMesh);
    }
  }

  if(m_bClipPlaneEnabled && (m_bClipVolume || m_bClipMesh)) {
    PLANE<float> transformed = m_ClipPlane * m_matView;
    const FLOATVECTOR3 normal(transformed.xyz());
    const float d = transformed.d();
    m_vSliceTriangles = ClipTriangles(m_vSliceTriangles, normal, d);
  }

}

// Checks the ordering of two points relative to a third.
static bool CheckOrdering(const FLOATVECTOR3& a,
                          const FLOATVECTOR3& b,
                          const FLOATVECTOR3& c) {
  float g1 = (a.y-c.y)/(a.x-c.x),
        g2 = (b.y-c.y)/(b.x-c.x);

  if (EpsilonEqual(a.x,c.x))
    return (g2 < 0) || (EpsilonEqual(g2,0.0f) && b.x < c.x);
  if (EpsilonEqual(b.x,c.x))
    return (g1 > 0) || (EpsilonEqual(g1,0.0f) && a.x > c.x);

  if (a.x < c.x)
    if (b.x < c.x) return g1 < g2; else return false;
  else
    if (b.x < c.x) return true; else return g1 < g2;
}

/// @todo: should be replaced with std::sort.
static void SortPoints(std::vector<VERTEX_FORMAT> &fArray) {
  // for small arrays, this bubble sort actually beats qsort.
  for (uint32_t i= 1;i<fArray.size();++i)
    for (uint32_t j = 1;j<fArray.size()-i;++j)
      if (!CheckOrdering(fArray[j].m_vPos,fArray[j+1].m_vPos,fArray[0].m_vPos))
        std::swap(fArray[j], fArray[j+1]);
}
<|endoftext|>


<commit_before>/*
 * Copyright 2013 Jonathan R. Guthrie
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * 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 "appendhandler.hpp"
#include "imapmaster.hpp"

ImapHandler *appendHandler(ImapSession *session, INPUT_DATA_STRUCT &input) {
    (void) input;
    return new AppendHandler(session, session->parseBuffer(), session->store());
}

// Parse stage is 0 if it doesn't have a mailbox name, and 1 if it is waiting for one, 2 if the name has arrived, and 3 if it's receiving message data.
IMAP_RESULTS AppendHandler::execute(INPUT_DATA_STRUCT &input) {
    IMAP_RESULTS result = IMAP_BAD;
    DateTime messageDateTime;

    if (m_parseStage < 3) {
	if ((2 < (input.dataLen - input.parsingAt)) && (' ' == input.data[input.parsingAt++])) {
	    if ('(' == input.data[input.parsingAt]) {
		++input.parsingAt;
		bool flagsOk;
		m_mailFlags = m_parseBuffer->readEmailFlags(input, flagsOk);
		if (flagsOk && (2 < (input.dataLen - input.parsingAt)) &&
		    (')' == input.data[input.parsingAt]) && (' ' == input.data[input.parsingAt+1])) {
		    input.parsingAt += 2;
		}
		else {
		    m_session->responseText("Malformed Command");
		    return IMAP_BAD;
		}
	    }
	    else {
		m_mailFlags = 0;
	    }

	    if ('"' == input.data[input.parsingAt]) {
		++input.parsingAt;
		// The constructor for DateTime swallows both the leading and trailing
		// double quote characters
		if (messageDateTime.parse(input.data, input.dataLen, input.parsingAt, DateTime::IMAP) &&
		    ('"' == input.data[input.parsingAt]) &&
		    (' ' == input.data[input.parsingAt+1])) {
		    input.parsingAt += 2;
		}
		else {
		    m_session->responseText("Malformed Command");
		    return IMAP_BAD;
		}
	    }

	    if ((2 < (input.dataLen - input.parsingAt)) && ('{' == input.data[input.parsingAt])) {
		// It's a literal string
		input.parsingAt++; // Skip the curly brace
		char *close;
		// read the number
		m_parseBuffer->literalLength(strtoul((char *)&input.data[input.parsingAt], &close, 10));
		// check for the close curly brace and end of message and to see if I can fit all that data
		// into the buffer
		size_t lastChar = (size_t) (close - ((char *)input.data));
		if ((NULL == close) || ('}' != close[0]) || (lastChar != (input.dataLen - 1))) {
		    m_session->responseText("Malformed Command");
		}
		else {
		    m_parseStage = 2;
		    result = IMAP_OK;
		}
	    }
	    else {
		m_session->responseText("Malformed Command");
		return IMAP_BAD;
	    }
	}
	else {
	    m_session->responseText("Malformed Command");
	    return IMAP_BAD;
	}
    }
    else {
	result = IMAP_OK;
    }

    MailStore::MAIL_STORE_RESULT mlr;
    m_tempMailboxName = m_parseBuffer->arguments();
    if (MailStore::SUCCESS == (mlr = m_store->lock(m_tempMailboxName))) {

	switch (m_store->addMessageToMailbox(m_tempMailboxName, m_session->lineBuffer(), 0, messageDateTime, m_mailFlags, &m_appendingUid)) {
	case MailStore::SUCCESS:
	    m_session->responseText("Ready for the Message Data");
	    m_parseStage = 3;
	    result = IMAP_NOTDONE;
	    break;

	case MailStore::CANNOT_COMPLETE_ACTION:
	    result = IMAP_TRY_AGAIN;
	    break;

	default:
	    result = IMAP_MBOX_ERROR;
	    break;
	}
    }
    else {
	result = IMAP_MBOX_ERROR;
	if (MailStore::CANNOT_COMPLETE_ACTION == mlr) {
	    result = IMAP_TRY_AGAIN;
	}
    }
    return result;
}

IMAP_RESULTS AppendHandler::receiveData(INPUT_DATA_STRUCT &input) {
    IMAP_RESULTS result = IMAP_OK;

    switch (m_parseStage) {
    case 0:
	switch (m_parseBuffer->astring(input, false, NULL)) {
	case ImapStringGood:
	    m_parseStage = 2;
	    result = execute(input);
	    break;

	case ImapStringBad:
	    m_session->responseText("Malformed Command");
	    result = IMAP_BAD;
	    break;

	case ImapStringPending:
	    result = IMAP_NOTDONE;
	    m_parseStage = 1;
	    break;

	default:
	    m_session->responseText("Failed -- internal error");
	    result = IMAP_NO;
	    break;
	}
	break;

    case 1:
	// It's the mailbox name that's arrived
    {
	size_t dataUsed = m_parseBuffer->addLiteralToParseBuffer(input);
	if (0 == m_parseBuffer->literalLength()) {
	    m_parseStage = 2;
	    if (2 < (input.dataLen - dataUsed)) {
		// Get rid of the CRLF if I have it
		input.dataLen -= 2;
		input.data[input.dataLen] = '\0';  // Make sure it's terminated so strchr et al work
	    }
	    result = execute(input);
	}
	else {
	    result = IMAP_IN_LITERAL;
	}
    }
    break;

    case 2:
    {
	result = execute(input);
    }
    break;

    case 3:
    {
	size_t residue;
	// It's the message body that's arrived
	size_t len = MIN(m_parseBuffer->literalLength(), input.dataLen);
	if (m_parseBuffer->literalLength() > input.dataLen) {
	    result = IMAP_IN_LITERAL;
	    residue = input.dataLen - m_parseBuffer->literalLength();
	}
	else {
	    residue = 0;
	}
	m_parseBuffer->literalLength(residue);
	std::string mailbox(m_parseBuffer->arguments());
	switch (m_store->appendDataToMessage(mailbox, m_appendingUid, input.data, len)) {
	case MailStore::SUCCESS:
	    result = IMAP_MBOX_ERROR;

	    if (0 == m_parseBuffer->literalLength()) {
		m_parseStage = 4;
		switch(m_store->doneAppendingDataToMessage(mailbox, m_appendingUid)) {
		case MailStore::SUCCESS:
		    if (MailStore::SUCCESS == m_store->unlock(m_tempMailboxName)) {
			result = IMAP_OK;
		    }
		    else {
			m_store->deleteMessage(mailbox, m_appendingUid);
			result = IMAP_MBOX_ERROR;
		    }
		    m_appendingUid = 0;
		    result = IMAP_OK;
		    break;

		case MailStore::CANNOT_COMPLETE_ACTION:
		    result = IMAP_TRY_AGAIN;
		    break;

		default:
		    m_store->deleteMessage(mailbox, m_appendingUid);
		    m_appendingUid = 0;
		    result = IMAP_MBOX_ERROR;
		}
	    }
	    break;

	case MailStore::CANNOT_COMPLETE_ACTION:
	    result = IMAP_TRY_AGAIN;
	    break;

	default:
	    m_store->doneAppendingDataToMessage(mailbox, m_appendingUid);
	    m_store->deleteMessage(mailbox, m_appendingUid);
	    m_store->unlock(m_tempMailboxName);
	    result = IMAP_MBOX_ERROR;
	    m_appendingUid = 0;
	    m_parseBuffer->literalLength(0);
	    break;
	}
    }
    break;

    case 4:
	// I've got the last of the data, and I'm retrying the done appending code
    {
	std::string mailbox(m_parseBuffer->arguments());
	switch(m_store->doneAppendingDataToMessage(mailbox, m_appendingUid)) {
	case MailStore::SUCCESS:
	    if (MailStore::SUCCESS == m_store->unlock(m_tempMailboxName)) {
		result = IMAP_OK;
	    }
	    else {
		m_store->deleteMessage(mailbox, m_appendingUid);
		result = IMAP_MBOX_ERROR;
	    }
	    m_appendingUid = 0;
	    break;

	case MailStore::CANNOT_COMPLETE_ACTION:
	    result = IMAP_TRY_AGAIN;
	    break;

	default:
	    m_store->deleteMessage(mailbox, m_appendingUid);
	    m_appendingUid = 0;
	    result = IMAP_MBOX_ERROR;
	}
	m_tempMailboxName = "";
    }
    break;

    default:
	m_session->responseText("Failed -- internal error");
	result = IMAP_NO;
	break;
    }
    return result;
}
<commit_msg>I am slowly working my way down the coverage tests.  I noted that there was a branch that was missed and it was associated with receiving the message data in multiple chunks, so I set up a test for that, and found a couple of errors associated with it, which I have now fixed.<commit_after>/*
 * Copyright 2013 Jonathan R. Guthrie
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * 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 "appendhandler.hpp"
#include "imapmaster.hpp"

ImapHandler *appendHandler(ImapSession *session, INPUT_DATA_STRUCT &input) {
    (void) input;
    return new AppendHandler(session, session->parseBuffer(), session->store());
}

// Parse stage is 0 if it doesn't have a mailbox name, and 1 if it is waiting for one, 2 if the name has arrived, and 3 if it's receiving message data.
IMAP_RESULTS AppendHandler::execute(INPUT_DATA_STRUCT &input) {
    IMAP_RESULTS result = IMAP_BAD;
    DateTime messageDateTime;

    if (m_parseStage < 3) {
	if ((2 < (input.dataLen - input.parsingAt)) && (' ' == input.data[input.parsingAt++])) {
	    if ('(' == input.data[input.parsingAt]) {
		++input.parsingAt;
		bool flagsOk;
		m_mailFlags = m_parseBuffer->readEmailFlags(input, flagsOk);
		if (flagsOk && (2 < (input.dataLen - input.parsingAt)) &&
		    (')' == input.data[input.parsingAt]) && (' ' == input.data[input.parsingAt+1])) {
		    input.parsingAt += 2;
		}
		else {
		    m_session->responseText("Malformed Command");
		    return IMAP_BAD;
		}
	    }
	    else {
		m_mailFlags = 0;
	    }

	    if ('"' == input.data[input.parsingAt]) {
		++input.parsingAt;
		// The constructor for DateTime swallows both the leading and trailing
		// double quote characters
		if (messageDateTime.parse(input.data, input.dataLen, input.parsingAt, DateTime::IMAP) &&
		    ('"' == input.data[input.parsingAt]) &&
		    (' ' == input.data[input.parsingAt+1])) {
		    input.parsingAt += 2;
		}
		else {
		    m_session->responseText("Malformed Command");
		    return IMAP_BAD;
		}
	    }

	    if ((2 < (input.dataLen - input.parsingAt)) && ('{' == input.data[input.parsingAt])) {
		// It's a literal string
		input.parsingAt++; // Skip the curly brace
		char *close;
		// read the number
		m_parseBuffer->literalLength(strtoul((char *)&input.data[input.parsingAt], &close, 10));
		// check for the close curly brace and end of message and to see if I can fit all that data
		// into the buffer
		size_t lastChar = (size_t) (close - ((char *)input.data));
		if ((NULL == close) || ('}' != close[0]) || (lastChar != (input.dataLen - 1))) {
		    m_session->responseText("Malformed Command");
		}
		else {
		    m_parseStage = 2;
		    result = IMAP_OK;
		}
	    }
	    else {
		m_session->responseText("Malformed Command");
		return IMAP_BAD;
	    }
	}
	else {
	    m_session->responseText("Malformed Command");
	    return IMAP_BAD;
	}
    }
    else {
	result = IMAP_OK;
    }

    MailStore::MAIL_STORE_RESULT mlr;
    m_tempMailboxName = m_parseBuffer->arguments();
    if (MailStore::SUCCESS == (mlr = m_store->lock(m_tempMailboxName))) {

	switch (m_store->addMessageToMailbox(m_tempMailboxName, m_session->lineBuffer(), 0, messageDateTime, m_mailFlags, &m_appendingUid)) {
	case MailStore::SUCCESS:
	    m_session->responseText("Ready for the Message Data");
	    m_parseStage = 3;
	    result = IMAP_NOTDONE;
	    break;

	case MailStore::CANNOT_COMPLETE_ACTION:
	    result = IMAP_TRY_AGAIN;
	    break;

	default:
	    result = IMAP_MBOX_ERROR;
	    break;
	}
    }
    else {
	result = IMAP_MBOX_ERROR;
	if (MailStore::CANNOT_COMPLETE_ACTION == mlr) {
	    result = IMAP_TRY_AGAIN;
	}
    }
    return result;
}

IMAP_RESULTS AppendHandler::receiveData(INPUT_DATA_STRUCT &input) {
    IMAP_RESULTS result = IMAP_OK;

    switch (m_parseStage) {
    case 0:
	switch (m_parseBuffer->astring(input, false, NULL)) {
	case ImapStringGood:
	    m_parseStage = 2;
	    result = execute(input);
	    break;

	case ImapStringBad:
	    m_session->responseText("Malformed Command");
	    result = IMAP_BAD;
	    break;

	case ImapStringPending:
	    result = IMAP_NOTDONE;
	    m_parseStage = 1;
	    break;

	default:
	    m_session->responseText("Failed -- internal error");
	    result = IMAP_NO;
	    break;
	}
	break;

    case 1:
	// It's the mailbox name that's arrived
    {
	size_t dataUsed = m_parseBuffer->addLiteralToParseBuffer(input);
	if (0 == m_parseBuffer->literalLength()) {
	    m_parseStage = 2;
	    if (2 < (input.dataLen - dataUsed)) {
		// Get rid of the CRLF if I have it
		input.dataLen -= 2;
		input.data[input.dataLen] = '\0';  // Make sure it's terminated so strchr et al work
	    }
	    result = execute(input);
	}
	else {
	    result = IMAP_IN_LITERAL;
	}
    }
    break;

    case 2:
    {
	result = execute(input);
    }
    break;

    case 3:
    {
	size_t residue;
	// It's the message body that's arrived
	size_t len = MIN(m_parseBuffer->literalLength(), input.dataLen);
	if (m_parseBuffer->literalLength() > input.dataLen) {
	    result = IMAP_IN_LITERAL;
	    residue = m_parseBuffer->literalLength() - input.dataLen;
	}
	else {
	    residue = 0;
	}
	m_parseBuffer->literalLength(residue);
	std::string mailbox(m_parseBuffer->arguments());
	switch (m_store->appendDataToMessage(mailbox, m_appendingUid, input.data, len)) {
	case MailStore::SUCCESS:
	    if (0 == m_parseBuffer->literalLength()) {
		m_parseStage = 4;
		switch(m_store->doneAppendingDataToMessage(mailbox, m_appendingUid)) {
		case MailStore::SUCCESS:
		    if (MailStore::SUCCESS == m_store->unlock(m_tempMailboxName)) {
			result = IMAP_OK;
		    }
		    else {
			m_store->deleteMessage(mailbox, m_appendingUid);
			result = IMAP_MBOX_ERROR;
		    }
		    m_appendingUid = 0;
		    result = IMAP_OK;
		    break;

		case MailStore::CANNOT_COMPLETE_ACTION:
		    result = IMAP_TRY_AGAIN;
		    break;

		default:
		    m_store->deleteMessage(mailbox, m_appendingUid);
		    m_appendingUid = 0;
		    result = IMAP_MBOX_ERROR;
		}
	    }
	    break;

	case MailStore::CANNOT_COMPLETE_ACTION:
	    result = IMAP_TRY_AGAIN;
	    break;

	default:
	    m_store->doneAppendingDataToMessage(mailbox, m_appendingUid);
	    m_store->deleteMessage(mailbox, m_appendingUid);
	    m_store->unlock(m_tempMailboxName);
	    result = IMAP_MBOX_ERROR;
	    m_appendingUid = 0;
	    m_parseBuffer->literalLength(0);
	    break;
	}
    }
    break;

    case 4:
	// I've got the last of the data, and I'm retrying the done appending code
    {
	std::string mailbox(m_parseBuffer->arguments());
	switch(m_store->doneAppendingDataToMessage(mailbox, m_appendingUid)) {
	case MailStore::SUCCESS:
	    if (MailStore::SUCCESS == m_store->unlock(m_tempMailboxName)) {
		result = IMAP_OK;
	    }
	    else {
		m_store->deleteMessage(mailbox, m_appendingUid);
		result = IMAP_MBOX_ERROR;
	    }
	    m_appendingUid = 0;
	    break;

	case MailStore::CANNOT_COMPLETE_ACTION:
	    result = IMAP_TRY_AGAIN;
	    break;

	default:
	    m_store->deleteMessage(mailbox, m_appendingUid);
	    m_appendingUid = 0;
	    result = IMAP_MBOX_ERROR;
	}
	m_tempMailboxName = "";
    }
    break;

    default:
	m_session->responseText("Failed -- internal error");
	result = IMAP_NO;
	break;
    }
    return result;
}
<|endoftext|>


<commit_before>//
//  GvmClusterMain.cpp
//  GvmCpp
//
//  Created by Mo DeJong on 8/14/15.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//

#include <iostream>

#import "Gvm.hpp"

using namespace std;
using namespace Gvm;

int main(int argc, char **argv) {
//  fprintf(stdout, "hello world\n");

  // The cluster "key" is a list of int values that correspond
  // to a certain coordinate.

  typedef void ClusterKey;

  GvmVectorSpace<double> vspace(3);

  const int numClusters = 2;

  GvmClusters<GvmVectorSpace<double>, ClusterKey, double> clusters(vspace, numClusters);

  // Generate list of 3D points

  double p1[] = { 0.0, 0.0, 0.0 };
  double p2[] = { 10.0, 10.0, 10.0 };
  double p3[] = { 1.0, 1.0, 1.0 };

  vector<vector<double> > listOfPoints;

  vector<double> points;

  points.clear();
  points.push_back(p1[0]);
  points.push_back(p1[1]);
  points.push_back(p1[2]);
  listOfPoints.push_back(points);

  points.clear();
  points.push_back(p2[0]);
  points.push_back(p2[1]);
  points.push_back(p2[2]);
  listOfPoints.push_back(points);

  points.clear();
  points.push_back(p3[0]);
  points.push_back(p3[1]);
  points.push_back(p3[2]);
  listOfPoints.push_back(points);

  for ( vector<double> & pt : listOfPoints ) {
    // Key is a list of (list of points)
    cout << "clustering point " << pt[0] << " " << pt[1] << " " << pt[2] << endl;
    clusters.add(1, pt, nullptr);
  }

  cout << "generated " << clusters.clusters.size() << " clusters" << endl;

  // vector<GvmResult>

  int clusteri = 0;

  for ( auto & result : clusters.results() ) {
    cout << "cluster[" << clusteri << "]: " << result.toString() << endl;
    clusteri++;
  }

  // Reduce down to 1 cluster

  cout << "reduce " << endl;

  clusters.reduce(-1.0, 1);

  clusteri = 0;

  for ( auto & result : clusters.results() ) {
    cout << "cluster[" << clusteri << "]: " << result.toString() << endl;
    clusteri++;
  }

  return 0;
}
<commit_msg>implement LUT based dumping logic after splitting pixels into clusters with double calculations<commit_after>//
//  GvmClusterMain.cpp
//  GvmCpp
//
//  Created by Mo DeJong on 8/14/15.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//

#include <iostream>

#include <unordered_map>

#import "Gvm.hpp"

using namespace std;
using namespace Gvm;

// Load points from a file

vector<vector<double> > loadPointsFromBGR(string filename)
{
  vector<vector<double> > allPoints;

  FILE *fp = fopen(filename.c_str(), "rb");

  fseek(fp, 0, SEEK_END);

  int numBytes = (int) ftell(fp);

  if (numBytes == 0) {
    cerr << "empty input YUV file contains zero BGRA pixels" << endl;
    exit(1);
  }

  if ((numBytes % sizeof(uint32_t)) != 0) {
    cerr << "input YUV must be a file with a whole number of BGRA pixels" << endl;
    exit(1);
  }

  fseek(fp, 0, SEEK_SET);

  // In DEBUG mode, use unordered_map to check for duplicate pixels in the input

#if defined(DEBUG)
  unordered_map<uint32_t, uint32_t> uniquePixelMap;
#endif // DEBUG

  for (; numBytes > 0 ; numBytes -= 4) {
    uint32_t pixel;

    int numRead = (int)fread(&pixel, sizeof(pixel), 1, fp);
    if (numRead != 1) {
      cerr << "could not read whole pixel from YUV input at offset " << ftell(fp) << endl;
      exit(1);
    }

    uint32_t B = pixel & 0xFF;
    uint32_t G = (pixel >> 8) & 0xFF;
    uint32_t R = (pixel >> 16) & 0xFF;

#if defined(DEBUG)
    uint32_t pixelNoAlpha = (R << 16) | (G << 8) | B;

    if (uniquePixelMap.count(pixelNoAlpha) > 0) {
      cerr << "input contains duplicate BGR pixel" << endl;
      exit(1);
    }
#endif // DEBUG

    double x = B;
    double y = G;
    double z = R;

    vector<double> coords;

    coords.push_back(x);
    coords.push_back(y);
    coords.push_back(z);

    allPoints.push_back(coords);
  }

  fclose(fp);

  return allPoints;
}

int main(int argc, char **argv) {

  string filename = "/Users/modejong/Development/ImageCompression/GVMCluster/Lenna_int_order.yuv";

  vector<vector<double> > allPoints = loadPointsFromBGR(filename);

  cout << "read " << allPoints.size() << " pixels from " << filename << endl;

  typedef vector<vector<double> > ClusterKey;

  GvmVectorSpace<double> vspace(3);

  const int numClusters = 2048;

  GvmClusters<GvmVectorSpace<double>, ClusterKey, double> clusters(vspace, numClusters);

  GvmListKeyer<GvmVectorSpace<double>, ClusterKey, double> intListKeyer;

  // Install key combiner for list of points, caller must manage ptr lifetime

  clusters.setKeyer(&intListKeyer);

  // Insert each point into clusters. Each point is
  // associated with a list of points called a "key".
  // This key object lifetime must be managed by the caller
  // for performance reasons.

  vector<ClusterKey> allKeys;
  allKeys.reserve(allPoints.size());

  for ( vector<double> & pt : allPoints ) {
    // Key is a list of (list of points)
    if (false) {
    assert(pt.size() == 3);
    cout << "clustering point (B G R) (" << pt[0] << " " << pt[1] << " " << pt[2] << ")" << endl;
    }

    allKeys.push_back(ClusterKey ());
    ClusterKey *key = &allKeys[allKeys.size() - 1];
    key->push_back(pt);

    clusters.add(1, pt, key);
  }

  cout << "generated " << clusters.clusters.size() << " clusters" << endl;

  // Emit clustered results as YUV data padded out to 256 with zeros

  // vector<GvmResult>

  int clusteri = 0;

  vector<GvmResult<GvmVectorSpace<double>, ClusterKey, double>> results = clusters.results();

  for ( auto & result : results ) {
    cout << "cluster[" << clusteri << "]: " << result.toString() << endl;
    clusteri++;
  }

  // Write clustered pixels as YUV output

  int totalPixelsWritten = 0;

  string outYuvFilename = "out.yuv";

  FILE *outFP = fopen(outYuvFilename.c_str(), "wb");

  for (int i = 0; i < results.size(); i++) {
    int clusterID = i; // keep to byte range

    ClusterKey *allKeys = results[i].getKey();

    cout << "cluster " << clusterID << " contains " << allKeys->size() << " pixels" << endl;

    int pixelsWritten = 0;

    for ( vector<double> &coord : *allKeys ) {
      uint32_t x = coord[0];
      uint32_t y = coord[1];
      uint32_t z = coord[2];

      if (x < 0 || x > 255) {
        assert(0);
      }
      if (y < 0 || y > 255) {
        assert(0);
      }
      if (z < 0 || z > 255) {
        assert(0);
      }

      uint32_t B = int(x);
      uint32_t G = int(y);
      uint32_t R = int(z);

      uint32_t pixel = (R << 16) | (G << 8) | B;

      int numWritten = (int)fwrite(&pixel, sizeof(uint32_t), 1, outFP);
      assert(numWritten == 1);
      pixelsWritten++;
    }

    totalPixelsWritten += pixelsWritten;

    if (true) {
      // Pad each cluster out to 256

      int numPointsInCluster = pixelsWritten;

      int over = numPointsInCluster % 256;
      int under = 0;

      if (over == 0) {
        // Cluster of exactly 256 pixels, emit 256 zeros to indicate this case.
        under = 256;
      } else {
        under = 256 - over;
      }

      for (int j = 0; j < under; j++) {
        uint32_t pixel = 0;
        int numWritten = (int)fwrite(&pixel, sizeof(uint32_t), 1, outFP);
        assert(numWritten == 1);
        totalPixelsWritten++;
      }
    }
  }

  fclose(outFP);

  cout << "wrote " << totalPixelsWritten << " total pixels to " << outYuvFilename << endl;

  int totalRowsOf256 = totalPixelsWritten/256;
  if ((totalPixelsWritten % 256) != 0) {
    assert(0);
  }

  cout << "wrote 256 x " << totalRowsOf256 << endl;

  cout << "as " << results.size() << " number of clusters" << endl;

  return 0;
}
<|endoftext|>


<commit_before>/*************************************************************************
 *
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
 *
 * Copyright 2008 by Sun Microsystems, Inc.
 *
 * OpenOffice.org - a multi-platform office productivity suite
 *
 * $RCSfile: textliststyle.hxx,v $
 * $Revision: 1.3 $
 *
 * This file is part of OpenOffice.org.
 *
 * OpenOffice.org is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License version 3
 * only, as published by the Free Software Foundation.
 *
 * OpenOffice.org 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 version 3 for more details
 * (a copy is included in the LICENSE file that accompanied this code).
 *
 * You should have received a copy of the GNU Lesser General Public License
 * version 3 along with OpenOffice.org.  If not, see
 * <http://www.openoffice.org/license.html>
 * for a copy of the LGPLv3 License.
 *
 ************************************************************************/

#ifndef OOX_DRAWINGML_TEXTLISTSTYLE_HXX
#define OOX_DRAWINGML_TEXTLISTSTYLE_HXX

#include "oox/drawingml/textparagraphproperties.hxx"
#include <boost/shared_ptr.hpp>
#include <vector>

namespace oox { namespace drawingml {

class TextListStyle;

typedef boost::shared_ptr< TextListStyle > TextListStylePtr;

class TextListStyle
{
public:

    TextListStyle();
    ~TextListStyle();

    void apply( const oox::drawingml::TextListStylePtr& rTextListStylePtr );

    std::vector< ::oox::drawingml::TextParagraphPropertiesPtr >& getListStyle() { return maListStyle; };
    std::vector< ::oox::drawingml::TextParagraphPropertiesPtr >& getAggregationListStyle() { return maAggregationListStyle; };

protected:

    std::vector< ::oox::drawingml::TextParagraphPropertiesPtr > maListStyle;
    std::vector< ::oox::drawingml::TextParagraphPropertiesPtr > maAggregationListStyle;
};

} }

#endif  //  OOX_DRAWINGML_TEXTLISTSTYLE_HXX
<commit_msg>INTEGRATION: CWS xmlfilter04 (1.2.12); FILE MERGED 2008/03/13 13:30:53 dr 1.2.12.1: make darwingml::TextBodyContext independent from drawingml::Shape, add various chart contexts<commit_after>/*************************************************************************
 *
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
 *
 * Copyright 2008 by Sun Microsystems, Inc.
 *
 * OpenOffice.org - a multi-platform office productivity suite
 *
 * $RCSfile: textliststyle.hxx,v $
 * $Revision: 1.4 $
 *
 * This file is part of OpenOffice.org.
 *
 * OpenOffice.org is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License version 3
 * only, as published by the Free Software Foundation.
 *
 * OpenOffice.org 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 version 3 for more details
 * (a copy is included in the LICENSE file that accompanied this code).
 *
 * You should have received a copy of the GNU Lesser General Public License
 * version 3 along with OpenOffice.org.  If not, see
 * <http://www.openoffice.org/license.html>
 * for a copy of the LGPLv3 License.
 *
 ************************************************************************/

#ifndef OOX_DRAWINGML_TEXTLISTSTYLE_HXX
#define OOX_DRAWINGML_TEXTLISTSTYLE_HXX

#include "oox/helper/containerhelper.hxx"
#include "oox/drawingml/textparagraphproperties.hxx"

namespace oox { namespace drawingml {

typedef RefVector< TextParagraphProperties > TextParagraphPropertiesVector;

class TextListStyle
{
public:

    TextListStyle();
    ~TextListStyle();

    void apply( const TextListStyle& rTextListStyle );

    inline const TextParagraphPropertiesVector& getListStyle() const { return maListStyle; };
    inline TextParagraphPropertiesVector&       getListStyle() { return maListStyle; };

    inline const TextParagraphPropertiesVector& getAggregationListStyle() const { return maAggregationListStyle; };
    inline TextParagraphPropertiesVector&       getAggregationListStyle() { return maAggregationListStyle; };

protected:

    TextParagraphPropertiesVector maListStyle;
    TextParagraphPropertiesVector maAggregationListStyle;
};

typedef boost::shared_ptr< TextListStyle > TextListStylePtr;

} }

#endif  //  OOX_DRAWINGML_TEXTLISTSTYLE_HXX
<|endoftext|>


<commit_before>/**
 * @file april_tags.cpp
 * @brief Example application for April tags library
 * @author: Michael Kaess
 *
 * Opens the first available camera (typically a built in camera in a
 * laptop) and continuously detects April tags in the incoming
 * images. Detections are both visualized in the live image and shown
 * in the text console. Optionally allows selecting of a specific
 * camera in case multiple ones are present and specifying image
 * resolution as long as supported by the camera. Also includes the
 * option to send tag detections via a serial port, for example when
 * running on a Raspberry Pi that is connected to an Arduino.
 */

using namespace std;

#include <iostream>
#include <cstring>
#include <vector>
#include <sys/time.h>

const string usage = "\n"
  "Usage:\n"
  "  apriltags_demo [OPTION...] [deviceID]\n"
  "\n"
  "Options:\n"
  "  -h  -?          Show help options\n"
  "  -a              Arduino (send tag ids over serial port)\n"
  "  -d              disable graphics\n"
  "  -C <bbxhh>      Tag family (default 36h11)\n"
  "  -F <fx>         Focal length in pixels\n"
  "  -W <width>      Image width (default 640, availability depends on camera)\n"
  "  -H <height>     Image height (default 480, availability depends on camera)\n"
  "  -S <size>       Tag size (square black frame) in meters\n"
  "  -E <exposure>   Manually set camera exposure (default auto; range 0-10000)\n"
  "  -G <gain>       Manually set camera gain (default auto; range 0-255)\n"
  "  -B <brightness> Manually set the camera brightness (default 128; range 0-255)\n"
  "\n";

const string intro = "\n"
    "April tags test code\n"
    "(C) 2012-2013 Massachusetts Institute of Technology\n"
    "Michael Kaess\n"
    "\n";

#define EXPOSURE_CONTROL // only works in Linux

#ifdef EXPOSURE_CONTROL
#include <libv4l2.h>
#include <linux/videodev2.h>
#include <fcntl.h>
#include <errno.h>
#endif

// OpenCV library for easy access to USB camera and drawing of images
// on screen
#include "opencv2/opencv.hpp"

// April tags detector and various families that can be selected by command line option
#include "AprilTags/TagDetector.h"
#include "AprilTags/Tag16h5.h"
#include "AprilTags/Tag25h7.h"
#include "AprilTags/Tag25h9.h"
#include "AprilTags/Tag36h9.h"
#include "AprilTags/Tag36h11.h"

// Needed for getopt / command line options processing
#include <unistd.h>
extern int optind;
extern char *optarg;

// For Arduino: locally defined serial port access class
#include "Serial.h"

const char* window_name = "apriltags_demo";

// utility function to provide current system time (used below in
// determining frame rate at which images are being processed)
double tic() {
  struct timeval t;
  gettimeofday(&t, NULL);
  return ((double)t.tv_sec + ((double)t.tv_usec)/1000000.);
}

class Demo {

  AprilTags::TagDetector* m_tagDetector;
  AprilTags::TagCodes m_tagCodes;

  bool m_draw; // draw image and April tag detections?
  bool m_arduino; // send tag detections to serial port?

  int m_width; // image size in pixels
  int m_height;
  double m_tagSize; // April tag side length in meters of square black frame
  double m_fx; // camera focal length in pixels
  double m_fy;
  double m_px; // camera principal point
  double m_py;

  int m_deviceId; // camera id (in case of multiple cameras)
  cv::VideoCapture m_cap;

  int m_exposure;
  int m_gain;
  int m_brightness;

  Serial m_serial;

public:

  // default constructor
  Demo() :
    // default settings, most can be modified through command line options (see below)
    m_tagDetector(NULL),
    m_tagCodes(AprilTags::tagCodes36h11),

    m_draw(true),
    m_arduino(false),

    m_width(640),
    m_height(480),
    m_tagSize(0.166),
    m_fx(600),
    m_fy(600),
    m_px(m_width/2),
    m_py(m_height/2),

    m_exposure(-1),
    m_gain(-1),
    m_brightness(-1),

    m_deviceId(0)
  {}

  // changing the tag family
  void setTagCodes(string s) {
    if (s=="16h5") {
      m_tagCodes = AprilTags::tagCodes16h5;
    } else if (s=="25h7") {
      m_tagCodes = AprilTags::tagCodes25h7;
    } else if (s=="25h9") {
      m_tagCodes = AprilTags::tagCodes25h9;
    } else if (s=="36h9") {
      m_tagCodes = AprilTags::tagCodes36h9;
    } else if (s=="36h11") {
      m_tagCodes = AprilTags::tagCodes36h11;
    } else {
      cout << "Invalid tag family specified" << endl;
      exit(1);
    }
  }

  // parse command line options to change default behavior
  void parseOptions(int argc, char* argv[]) {
    int c;
    while ((c = getopt(argc, argv, ":h?adC:F:H:S:W:E:G:B:")) != -1) {
      // Each option character has to be in the string in getopt();
      // the first colon changes the error character from '?' to ':';
      // a colon after an option means that there is an extra
      // parameter to this option; 'W' is a reserved character
      switch (c) {
      case 'h':
      case '?':
        cout << intro;
        cout << usage;
        exit(0);
        break;
      case 'a':
        m_arduino = true;
        break;
      case 'd':
        m_draw = false;
        break;
      case 'C':
        setTagCodes(optarg);
        break;
      case 'F':
        m_fx = atof(optarg);
        m_fy = m_fx;
        break;
      case 'H':
        m_height = atoi(optarg);
        m_py = m_height/2;
         break;
      case 'S':
        m_tagSize = atof(optarg);
        break;
      case 'W':
        m_width = atoi(optarg);
        m_px = m_width/2;
        break;
      case 'E':
        m_exposure = atoi(optarg);
        break;
      case 'G':
        m_gain = atoi(optarg);
        break;
      case 'B':
        m_brightness = atoi(optarg);
        break;
      case ':': // unknown option, from getopt
        cout << intro;
        cout << usage;
        exit(1);
        break;
      }
    }

    if (argc == optind + 1) {
      m_deviceId = atoi(argv[optind]);
    }
  }

  void setup() {
    m_tagDetector = new AprilTags::TagDetector(m_tagCodes);

#ifdef EXPOSURE_CONTROL
    // manually setting camera exposure settings; OpenCV/v4l1 doesn't
    // support exposure control; so here we manually use v4l2 before
    // opening the device via OpenCV; confirmed to work with Logitech
    // C270; try exposure=20, gain=100, brightness=150

    string video_str = "/dev/video0";
    video_str[10] = '0' + m_deviceId;
    int device = v4l2_open(video_str.c_str(), O_RDWR | O_NONBLOCK);

    if (m_exposure >= 0) {
      // not sure why, but v4l2_set_control() does not work for
      // V4L2_CID_EXPOSURE_AUTO...
      struct v4l2_control c;
      c.id = V4L2_CID_EXPOSURE_AUTO;
      c.value = 1; // 1=manual, 3=auto; V4L2_EXPOSURE_AUTO fails...
      if (v4l2_ioctl(device, VIDIOC_S_CTRL, &c) != 0) {
        cout << "Failed to set... " << strerror(errno) << endl;
      }
      cout << "exposure: " << m_exposure << endl;
      v4l2_set_control(device, V4L2_CID_EXPOSURE_ABSOLUTE, m_exposure*6);
    }
    if (m_gain >= 0) {
      cout << "gain: " << m_gain << endl;
      v4l2_set_control(device, V4L2_CID_GAIN, m_gain*256);
    }
    if (m_brightness >= 0) {
      cout << "brightness: " << m_brightness << endl;
      v4l2_set_control(device, V4L2_CID_BRIGHTNESS, m_brightness*256);
    }
    v4l2_close(device);
#endif

    // find and open a USB camera (built in laptop camera, web cam etc)
    m_cap = cv::VideoCapture(m_deviceId);
        if(!m_cap.isOpened()) {
      cerr << "ERROR: Can't find video device " << m_deviceId << "\n";
      exit(1);
    }
    m_cap.set(CV_CAP_PROP_FRAME_WIDTH, m_width);
    m_cap.set(CV_CAP_PROP_FRAME_HEIGHT, m_height);
    cout << "Camera successfully opened (ignore error messages above...)" << endl;
    cout << "Actual resolution: "
         << m_cap.get(CV_CAP_PROP_FRAME_WIDTH) << "x"
         << m_cap.get(CV_CAP_PROP_FRAME_HEIGHT) << endl;

    // prepare window for drawing the camera images
    if (m_draw) {
      cv::namedWindow(window_name, 1);
    }

    // optional: prepare serial port for communication with Arduino
    if (m_arduino) {
      m_serial.open("/dev/ttyACM0");
    }
  }

  void print_detection(AprilTags::TagDetection& detection) const {
    cout << "  Id: " << detection.id
         << " (Hamming: " << detection.hammingDistance << ")";

    // recovering the relative pose of a tag:

    // NOTE: for this to be accurate, it is necessary to use the
    // actual camera parameters here as well as the actual tag size
    // (m_fx, m_fy, m_px, m_py, m_tagSize)

    Eigen::Vector3d translation;
    Eigen::Matrix3d rotation;
    detection.getRelativeTranslationRotation(m_tagSize, m_fx, m_fy, m_px, m_py,
                                             translation, rotation);

    cout << "  distance=" << translation.norm()
         << "m, x=" << translation(0)
         << ", y=" << translation(1)
         << ", z=" << translation(2)
         << endl;

    // Also note that for SLAM/multi-view application it is better to
    // use reprojection error of corner points, because the noise in
    // this relative pose is very non-Gaussian; see iSAM source code
    // for suitable factors.
  }

  // The processing loop where images are retrieved, tags detected,
  // and information about detections generated
  void loop() {

    cv::Mat image;
    cv::Mat image_gray;

    int frame = 0;
    double last_t = tic();
    while (true) {

      // capture frame
      m_cap >> image;

      // alternative way is to grab, then retrieve; allows for
      // multiple grab when processing below frame rate - v4l keeps a
      // number of frames buffered, which can lead to significant lag
      //      m_cap.grab();
      //      m_cap.retrieve(image);

      // detect April tags (requires a gray scale image)
      cv::cvtColor(image, image_gray, CV_BGR2GRAY);
      vector<AprilTags::TagDetection> detections = m_tagDetector->extractTags(image_gray);

      // print out each detection
      cout << detections.size() << " tags detected:" << endl;
      for (int i=0; i<detections.size(); i++) {
        print_detection(detections[i]);
      }

      // show the current image including any detections
      if (m_draw) {
        for (int i=0; i<detections.size(); i++) {
          // also highlight in the image
          detections[i].draw(image);
        }
        imshow(window_name, image); // OpenCV call
      }

      // optionally send tag information to serial port (e.g. to Arduino)
      if (m_arduino) {
        if (detections.size() > 0) {
          // only the first detected tag is sent out for now
          Eigen::Vector3d translation;
          Eigen::Matrix3d rotation;
          detections[0].getRelativeTranslationRotation(m_tagSize, m_fx, m_fy, m_px, m_py,
                                                       translation, rotation);
          m_serial.print(detections[0].id);
          m_serial.print(",");
          m_serial.print(translation(0));
          m_serial.print(",");
          m_serial.print(translation(1));
          m_serial.print(",");
          m_serial.print(translation(2));
          m_serial.print("\n");
        } else {
          // no tag detected: tag ID = -1
          m_serial.print("-1,0.0,0.0,0.0\n");
        }
      }

      // print out the frame rate at which image frames are being processed
      frame++;
      if (frame % 10 == 0) {
        double t = tic();
        cout << "  " << 10./(t-last_t) << " fps" << endl;
        last_t = t;
      }

      // exit if any key is pressed
      if (cv::waitKey(1) >= 0) break;
    }
  }

}; // Demo

// here is were everything begins
int main(int argc, char* argv[]) {
  Demo demo;

  // process command line options
  demo.parseOptions(argc, argv);

  // setup image source, window for drawing, serial port...
  demo.setup();

  // the actual processing loop where tags are detected and visualized
  demo.loop();

  return 0;
}
<commit_msg>automatically disabling exposure/v4l on Mac<commit_after>/**
 * @file april_tags.cpp
 * @brief Example application for April tags library
 * @author: Michael Kaess
 *
 * Opens the first available camera (typically a built in camera in a
 * laptop) and continuously detects April tags in the incoming
 * images. Detections are both visualized in the live image and shown
 * in the text console. Optionally allows selecting of a specific
 * camera in case multiple ones are present and specifying image
 * resolution as long as supported by the camera. Also includes the
 * option to send tag detections via a serial port, for example when
 * running on a Raspberry Pi that is connected to an Arduino.
 */

using namespace std;

#include <iostream>
#include <cstring>
#include <vector>
#include <sys/time.h>

const string usage = "\n"
  "Usage:\n"
  "  apriltags_demo [OPTION...] [deviceID]\n"
  "\n"
  "Options:\n"
  "  -h  -?          Show help options\n"
  "  -a              Arduino (send tag ids over serial port)\n"
  "  -d              disable graphics\n"
  "  -C <bbxhh>      Tag family (default 36h11)\n"
  "  -F <fx>         Focal length in pixels\n"
  "  -W <width>      Image width (default 640, availability depends on camera)\n"
  "  -H <height>     Image height (default 480, availability depends on camera)\n"
  "  -S <size>       Tag size (square black frame) in meters\n"
  "  -E <exposure>   Manually set camera exposure (default auto; range 0-10000)\n"
  "  -G <gain>       Manually set camera gain (default auto; range 0-255)\n"
  "  -B <brightness> Manually set the camera brightness (default 128; range 0-255)\n"
  "\n";

const string intro = "\n"
    "April tags test code\n"
    "(C) 2012-2013 Massachusetts Institute of Technology\n"
    "Michael Kaess\n"
    "\n";

#ifndef __APPLE__
#define EXPOSURE_CONTROL // only works in Linux
#endif

#ifdef EXPOSURE_CONTROL
#include <libv4l2.h>
#include <linux/videodev2.h>
#include <fcntl.h>
#include <errno.h>
#endif

// OpenCV library for easy access to USB camera and drawing of images
// on screen
#include "opencv2/opencv.hpp"

// April tags detector and various families that can be selected by command line option
#include "AprilTags/TagDetector.h"
#include "AprilTags/Tag16h5.h"
#include "AprilTags/Tag25h7.h"
#include "AprilTags/Tag25h9.h"
#include "AprilTags/Tag36h9.h"
#include "AprilTags/Tag36h11.h"

// Needed for getopt / command line options processing
#include <unistd.h>
extern int optind;
extern char *optarg;

// For Arduino: locally defined serial port access class
#include "Serial.h"

const char* window_name = "apriltags_demo";

// utility function to provide current system time (used below in
// determining frame rate at which images are being processed)
double tic() {
  struct timeval t;
  gettimeofday(&t, NULL);
  return ((double)t.tv_sec + ((double)t.tv_usec)/1000000.);
}

class Demo {

  AprilTags::TagDetector* m_tagDetector;
  AprilTags::TagCodes m_tagCodes;

  bool m_draw; // draw image and April tag detections?
  bool m_arduino; // send tag detections to serial port?

  int m_width; // image size in pixels
  int m_height;
  double m_tagSize; // April tag side length in meters of square black frame
  double m_fx; // camera focal length in pixels
  double m_fy;
  double m_px; // camera principal point
  double m_py;

  int m_deviceId; // camera id (in case of multiple cameras)
  cv::VideoCapture m_cap;

  int m_exposure;
  int m_gain;
  int m_brightness;

  Serial m_serial;

public:

  // default constructor
  Demo() :
    // default settings, most can be modified through command line options (see below)
    m_tagDetector(NULL),
    m_tagCodes(AprilTags::tagCodes36h11),

    m_draw(true),
    m_arduino(false),

    m_width(640),
    m_height(480),
    m_tagSize(0.166),
    m_fx(600),
    m_fy(600),
    m_px(m_width/2),
    m_py(m_height/2),

    m_exposure(-1),
    m_gain(-1),
    m_brightness(-1),

    m_deviceId(0)
  {}

  // changing the tag family
  void setTagCodes(string s) {
    if (s=="16h5") {
      m_tagCodes = AprilTags::tagCodes16h5;
    } else if (s=="25h7") {
      m_tagCodes = AprilTags::tagCodes25h7;
    } else if (s=="25h9") {
      m_tagCodes = AprilTags::tagCodes25h9;
    } else if (s=="36h9") {
      m_tagCodes = AprilTags::tagCodes36h9;
    } else if (s=="36h11") {
      m_tagCodes = AprilTags::tagCodes36h11;
    } else {
      cout << "Invalid tag family specified" << endl;
      exit(1);
    }
  }

  // parse command line options to change default behavior
  void parseOptions(int argc, char* argv[]) {
    int c;
    while ((c = getopt(argc, argv, ":h?adC:F:H:S:W:E:G:B:")) != -1) {
      // Each option character has to be in the string in getopt();
      // the first colon changes the error character from '?' to ':';
      // a colon after an option means that there is an extra
      // parameter to this option; 'W' is a reserved character
      switch (c) {
      case 'h':
      case '?':
        cout << intro;
        cout << usage;
        exit(0);
        break;
      case 'a':
        m_arduino = true;
        break;
      case 'd':
        m_draw = false;
        break;
      case 'C':
        setTagCodes(optarg);
        break;
      case 'F':
        m_fx = atof(optarg);
        m_fy = m_fx;
        break;
      case 'H':
        m_height = atoi(optarg);
        m_py = m_height/2;
         break;
      case 'S':
        m_tagSize = atof(optarg);
        break;
      case 'W':
        m_width = atoi(optarg);
        m_px = m_width/2;
        break;
      case 'E':
#ifndef EXPOSURE_CONTROL
        cout << "Error: Exposure option (-E) not available" << endl;
        exit(1);
#endif
        m_exposure = atoi(optarg);
        break;
      case 'G':
#ifndef EXPOSURE_CONTROL
        cout << "Error: Gain option (-G) not available" << endl;
        exit(1);
#endif
        m_gain = atoi(optarg);
        break;
      case 'B':
#ifndef EXPOSURE_CONTROL
        cout << "Error: Brightness option (-B) not available" << endl;
        exit(1);
#endif
        m_brightness = atoi(optarg);
        break;
      case ':': // unknown option, from getopt
        cout << intro;
        cout << usage;
        exit(1);
        break;
      }
    }

    if (argc == optind + 1) {
      m_deviceId = atoi(argv[optind]);
    }
  }

  void setup() {
    m_tagDetector = new AprilTags::TagDetector(m_tagCodes);

#ifdef EXPOSURE_CONTROL
    // manually setting camera exposure settings; OpenCV/v4l1 doesn't
    // support exposure control; so here we manually use v4l2 before
    // opening the device via OpenCV; confirmed to work with Logitech
    // C270; try exposure=20, gain=100, brightness=150

    string video_str = "/dev/video0";
    video_str[10] = '0' + m_deviceId;
    int device = v4l2_open(video_str.c_str(), O_RDWR | O_NONBLOCK);

    if (m_exposure >= 0) {
      // not sure why, but v4l2_set_control() does not work for
      // V4L2_CID_EXPOSURE_AUTO...
      struct v4l2_control c;
      c.id = V4L2_CID_EXPOSURE_AUTO;
      c.value = 1; // 1=manual, 3=auto; V4L2_EXPOSURE_AUTO fails...
      if (v4l2_ioctl(device, VIDIOC_S_CTRL, &c) != 0) {
        cout << "Failed to set... " << strerror(errno) << endl;
      }
      cout << "exposure: " << m_exposure << endl;
      v4l2_set_control(device, V4L2_CID_EXPOSURE_ABSOLUTE, m_exposure*6);
    }
    if (m_gain >= 0) {
      cout << "gain: " << m_gain << endl;
      v4l2_set_control(device, V4L2_CID_GAIN, m_gain*256);
    }
    if (m_brightness >= 0) {
      cout << "brightness: " << m_brightness << endl;
      v4l2_set_control(device, V4L2_CID_BRIGHTNESS, m_brightness*256);
    }
    v4l2_close(device);
#endif

    // find and open a USB camera (built in laptop camera, web cam etc)
    m_cap = cv::VideoCapture(m_deviceId);
        if(!m_cap.isOpened()) {
      cerr << "ERROR: Can't find video device " << m_deviceId << "\n";
      exit(1);
    }
    m_cap.set(CV_CAP_PROP_FRAME_WIDTH, m_width);
    m_cap.set(CV_CAP_PROP_FRAME_HEIGHT, m_height);
    cout << "Camera successfully opened (ignore error messages above...)" << endl;
    cout << "Actual resolution: "
         << m_cap.get(CV_CAP_PROP_FRAME_WIDTH) << "x"
         << m_cap.get(CV_CAP_PROP_FRAME_HEIGHT) << endl;

    // prepare window for drawing the camera images
    if (m_draw) {
      cv::namedWindow(window_name, 1);
    }

    // optional: prepare serial port for communication with Arduino
    if (m_arduino) {
      m_serial.open("/dev/ttyACM0");
    }
  }

  void print_detection(AprilTags::TagDetection& detection) const {
    cout << "  Id: " << detection.id
         << " (Hamming: " << detection.hammingDistance << ")";

    // recovering the relative pose of a tag:

    // NOTE: for this to be accurate, it is necessary to use the
    // actual camera parameters here as well as the actual tag size
    // (m_fx, m_fy, m_px, m_py, m_tagSize)

    Eigen::Vector3d translation;
    Eigen::Matrix3d rotation;
    detection.getRelativeTranslationRotation(m_tagSize, m_fx, m_fy, m_px, m_py,
                                             translation, rotation);

    cout << "  distance=" << translation.norm()
         << "m, x=" << translation(0)
         << ", y=" << translation(1)
         << ", z=" << translation(2)
         << endl;

    // Also note that for SLAM/multi-view application it is better to
    // use reprojection error of corner points, because the noise in
    // this relative pose is very non-Gaussian; see iSAM source code
    // for suitable factors.
  }

  // The processing loop where images are retrieved, tags detected,
  // and information about detections generated
  void loop() {

    cv::Mat image;
    cv::Mat image_gray;

    int frame = 0;
    double last_t = tic();
    while (true) {

      // capture frame
      m_cap >> image;

      // alternative way is to grab, then retrieve; allows for
      // multiple grab when processing below frame rate - v4l keeps a
      // number of frames buffered, which can lead to significant lag
      //      m_cap.grab();
      //      m_cap.retrieve(image);

      // detect April tags (requires a gray scale image)
      cv::cvtColor(image, image_gray, CV_BGR2GRAY);
      vector<AprilTags::TagDetection> detections = m_tagDetector->extractTags(image_gray);

      // print out each detection
      cout << detections.size() << " tags detected:" << endl;
      for (int i=0; i<detections.size(); i++) {
        print_detection(detections[i]);
      }

      // show the current image including any detections
      if (m_draw) {
        for (int i=0; i<detections.size(); i++) {
          // also highlight in the image
          detections[i].draw(image);
        }
        imshow(window_name, image); // OpenCV call
      }

      // optionally send tag information to serial port (e.g. to Arduino)
      if (m_arduino) {
        if (detections.size() > 0) {
          // only the first detected tag is sent out for now
          Eigen::Vector3d translation;
          Eigen::Matrix3d rotation;
          detections[0].getRelativeTranslationRotation(m_tagSize, m_fx, m_fy, m_px, m_py,
                                                       translation, rotation);
          m_serial.print(detections[0].id);
          m_serial.print(",");
          m_serial.print(translation(0));
          m_serial.print(",");
          m_serial.print(translation(1));
          m_serial.print(",");
          m_serial.print(translation(2));
          m_serial.print("\n");
        } else {
          // no tag detected: tag ID = -1
          m_serial.print("-1,0.0,0.0,0.0\n");
        }
      }

      // print out the frame rate at which image frames are being processed
      frame++;
      if (frame % 10 == 0) {
        double t = tic();
        cout << "  " << 10./(t-last_t) << " fps" << endl;
        last_t = t;
      }

      // exit if any key is pressed
      if (cv::waitKey(1) >= 0) break;
    }
  }

}; // Demo

// here is were everything begins
int main(int argc, char* argv[]) {
  Demo demo;

  // process command line options
  demo.parseOptions(argc, argv);

  // setup image source, window for drawing, serial port...
  demo.setup();

  // the actual processing loop where tags are detected and visualized
  demo.loop();

  return 0;
}
<|endoftext|>


<commit_before>// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "base/file_util.h"
#include "base/logging.h"
#include "base/path_service.h"
#include "chrome/browser/search_engines/template_url.h"
#include "chrome/browser/search_engines/template_url_parser.h"
#include "chrome/common/chrome_paths.h"
#include "testing/gtest/include/gtest/gtest.h"

class TemplateURLParserTest : public testing::Test {
 public:
  TemplateURLParserTest() : parse_result_(true) {
  }

  virtual void SetUp() {
    ASSERT_TRUE(PathService::Get(chrome::DIR_TEST_DATA, &full_path_));
    full_path_ = full_path_.AppendASCII("osdd");
    if (!file_util::PathExists(full_path_)) {
      LOG(ERROR) <<
          L"This test can't be run without some non-redistributable data";
      full_path_ = FilePath();
    }
  }

  bool IsDisabled() {
    return full_path_.empty();
  }

  // Parses the OpenSearch description document at file_name (relative to
  // the data dir). The TemplateURL is placed in template_url_.
  // The result of Parse is stored in the field parse_result_ (this doesn't
  // use a return value due to internally using ASSERT_).
  void ParseFile(const std::string& file_name,
                 TemplateURLParser::ParameterFilter* filter) {
    FilePath full_path;
    parse_result_ = false;
    ASSERT_TRUE(PathService::Get(chrome::DIR_TEST_DATA, &full_path));
    full_path = full_path.AppendASCII("osdd");
    full_path = full_path.AppendASCII(file_name);
    ASSERT_TRUE(file_util::PathExists(full_path));

    std::string contents;
    file_util::ReadFileToString(full_path, &contents);
    parse_result_ = TemplateURLParser::Parse(
        reinterpret_cast<const unsigned char*>(contents.c_str()),
        contents.length(), filter, &template_url_);
  }

  // ParseFile parses the results into this template_url.
  TemplateURL template_url_;

  FilePath full_path_;

  // Result of the parse.
  bool parse_result_;
};

TEST_F(TemplateURLParserTest, FailOnBogusURL) {
  if (IsDisabled())
    return;
  ParseFile("bogus.xml", NULL);
  EXPECT_FALSE(parse_result_);
}

TEST_F(TemplateURLParserTest, PassOnHTTPS) {
  if (IsDisabled())
    return;
  ParseFile("https.xml", NULL);
  EXPECT_TRUE(parse_result_);
}

TEST_F(TemplateURLParserTest, FailOnPost) {
  if (IsDisabled())
    return;
  ParseFile("post.xml", NULL);
  EXPECT_FALSE(parse_result_);
}

TEST_F(TemplateURLParserTest, TestDictionary) {
  if (IsDisabled())
    return;
  ParseFile("dictionary.xml", NULL);
  ASSERT_TRUE(parse_result_);
  EXPECT_EQ(L"Dictionary.com", template_url_.short_name());
  EXPECT_TRUE(template_url_.GetFavIconURL() ==
              GURL("http://cache.lexico.com/g/d/favicon.ico"));
  EXPECT_TRUE(template_url_.url() != NULL);
  EXPECT_TRUE(template_url_.url()->SupportsReplacement());
  EXPECT_EQ(template_url_.url()->url(),
            L"http://dictionary.reference.com/browse/{searchTerms}?r=75");
}

TEST_F(TemplateURLParserTest, TestMSDN) {
  if (IsDisabled())
    return;
  ParseFile("msdn.xml", NULL);
  ASSERT_TRUE(parse_result_);
  EXPECT_EQ(L"Search \" MSDN", template_url_.short_name());
  EXPECT_TRUE(template_url_.GetFavIconURL() ==
              GURL("http://search.msdn.microsoft.com/search/favicon.ico"));
  EXPECT_TRUE(template_url_.url() != NULL);
  EXPECT_TRUE(template_url_.url()->SupportsReplacement());
  EXPECT_EQ(template_url_.url()->url(),
            L"http://search.msdn.microsoft.com/search/default.aspx?Query={searchTerms}&brand=msdn&locale=en-US");
}

TEST_F(TemplateURLParserTest, TestWikipedia) {
  if (IsDisabled())
    return;
  ParseFile("wikipedia.xml", NULL);
  ASSERT_TRUE(parse_result_);
  EXPECT_EQ(L"Wikipedia (English)", template_url_.short_name());
  EXPECT_TRUE(template_url_.GetFavIconURL() ==
              GURL("http://en.wikipedia.org/favicon.ico"));
  EXPECT_TRUE(template_url_.url() != NULL);
  EXPECT_TRUE(template_url_.url()->SupportsReplacement());
  EXPECT_EQ(template_url_.url()->url(),
      L"http://en.wikipedia.org/w/index.php?title=Special:Search&search={searchTerms}");
  EXPECT_TRUE(template_url_.suggestions_url() != NULL);
  EXPECT_TRUE(template_url_.suggestions_url()->SupportsReplacement());
  EXPECT_EQ(template_url_.suggestions_url()->url(),
      L"http://en.wikipedia.org/w/api.php?action=opensearch&search={searchTerms}");
  ASSERT_EQ(2U, template_url_.input_encodings().size());
  EXPECT_EQ("UTF-8", template_url_.input_encodings()[0]);
  EXPECT_EQ("Shift_JIS", template_url_.input_encodings()[1]);
}

TEST_F(TemplateURLParserTest, NoCrashOnEmptyAttributes) {
  if (IsDisabled())
    return;
  ParseFile("url_with_no_attributes.xml", NULL);
}

// Filters any param which as an occurrence of name_str_ in its name or an
// occurrence of value_str_ in its value.
class ParamFilterImpl : public TemplateURLParser::ParameterFilter {
 public:
  ParamFilterImpl(std::string name_str, std::string value_str)
     : name_str_(name_str),
       value_str_(value_str) {
  }

  bool KeepParameter(const std::string& key, const std::string& value) {
    return (name_str_.empty() || key.find(name_str_) == std::string::npos) &&
           (value_str_.empty() || value.find(value_str_) == std::string::npos);
  }

 private:
  std::string name_str_;
  std::string value_str_;

  DISALLOW_EVIL_CONSTRUCTORS(ParamFilterImpl);
};

TEST_F(TemplateURLParserTest, TestFirefoxEbay) {
  if (IsDisabled())
    return;
  // This file uses the Parameter extension
  // (see http://www.opensearch.org/Specifications/OpenSearch/Extensions/Parameter/1.0)
  ParamFilterImpl filter("ebay", "ebay");
  ParseFile("firefox_ebay.xml", &filter);
  ASSERT_TRUE(parse_result_);
  EXPECT_EQ(L"eBay", template_url_.short_name());
  EXPECT_TRUE(template_url_.url() != NULL);
  EXPECT_TRUE(template_url_.url()->SupportsReplacement());
  std::wstring exp_url =
      L"http://search.ebay.com/search/search.dll?query={searchTerms}&"
      L"MfcISAPICommand=GetResult&ht=1&srchdesc=n&maxRecordsReturned=300&"
      L"maxRecordsPerPage=50&SortProperty=MetaEndSort";
  EXPECT_EQ(exp_url, template_url_.url()->url());
  ASSERT_EQ(1U, template_url_.input_encodings().size());
  EXPECT_EQ("ISO-8859-1", template_url_.input_encodings()[0]);
  EXPECT_EQ(GURL("http://search.ebay.com/favicon.ico"),
            template_url_.GetFavIconURL());
}

TEST_F(TemplateURLParserTest, TestFirefoxWebster) {
  if (IsDisabled())
    return;
  // This XML file uses a namespace.
  ParamFilterImpl filter("", "Mozilla");
  ParseFile("firefox_webster.xml", &filter);
  ASSERT_TRUE(parse_result_);
  EXPECT_EQ(L"Webster", template_url_.short_name());
  EXPECT_TRUE(template_url_.url() != NULL);
  EXPECT_TRUE(template_url_.url()->SupportsReplacement());
  EXPECT_EQ(L"http://www.webster.com/cgi-bin/dictionary?va={searchTerms}",
            template_url_.url()->url());
  ASSERT_EQ(1U, template_url_.input_encodings().size());
  EXPECT_EQ("ISO-8859-1", template_url_.input_encodings()[0]);
  EXPECT_EQ(GURL("http://www.webster.com/favicon.ico"),
            template_url_.GetFavIconURL());
}

TEST_F(TemplateURLParserTest, TestFirefoxYahoo) {
  if (IsDisabled())
    return;
  // This XML file uses a namespace.
  ParamFilterImpl filter("", "Mozilla");
  ParseFile("firefox_yahoo.xml", &filter);
  ASSERT_TRUE(parse_result_);
  EXPECT_EQ(L"Yahoo", template_url_.short_name());
  EXPECT_TRUE(template_url_.url() != NULL);
  EXPECT_TRUE(template_url_.url()->SupportsReplacement());
  EXPECT_EQ(L"http://ff.search.yahoo.com/gossip?"
            L"output=fxjson&command={searchTerms}",
            template_url_.suggestions_url()->url());
  EXPECT_EQ(L"http://search.yahoo.com/search?p={searchTerms}&ei=UTF-8",
            template_url_.url()->url());
  ASSERT_EQ(1U, template_url_.input_encodings().size());
  EXPECT_EQ("UTF-8", template_url_.input_encodings()[0]);
  EXPECT_EQ(GURL("http://search.yahoo.com/favicon.ico"),
            template_url_.GetFavIconURL());
}

// Make sure we ignore POST suggestions (this is the same XML file as
// firefox_yahoo.xml, the suggestion method was just changed to POST).
TEST_F(TemplateURLParserTest, TestPostSuggestion) {
  if (IsDisabled())
    return;
  // This XML file uses a namespace.
  ParamFilterImpl filter("", "Mozilla");
  ParseFile("post_suggestion.xml", &filter);
  ASSERT_TRUE(parse_result_);
  EXPECT_EQ(L"Yahoo", template_url_.short_name());
  EXPECT_TRUE(template_url_.url() != NULL);
  EXPECT_TRUE(template_url_.url()->SupportsReplacement());
  EXPECT_TRUE(template_url_.suggestions_url() == NULL);
  EXPECT_EQ(L"http://search.yahoo.com/search?p={searchTerms}&ei=UTF-8",
            template_url_.url()->url());
  ASSERT_EQ(1U, template_url_.input_encodings().size());
  EXPECT_EQ("UTF-8", template_url_.input_encodings()[0]);
  EXPECT_EQ(GURL("http://search.yahoo.com/favicon.ico"),
            template_url_.GetFavIconURL());
}
<commit_msg>Coverity: check file_util::ReadFileToString return.<commit_after>// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "base/file_util.h"
#include "base/logging.h"
#include "base/path_service.h"
#include "chrome/browser/search_engines/template_url.h"
#include "chrome/browser/search_engines/template_url_parser.h"
#include "chrome/common/chrome_paths.h"
#include "testing/gtest/include/gtest/gtest.h"

class TemplateURLParserTest : public testing::Test {
 public:
  TemplateURLParserTest() : parse_result_(true) {
  }

  virtual void SetUp() {
    ASSERT_TRUE(PathService::Get(chrome::DIR_TEST_DATA, &full_path_));
    full_path_ = full_path_.AppendASCII("osdd");
    if (!file_util::PathExists(full_path_)) {
      LOG(ERROR) <<
          L"This test can't be run without some non-redistributable data";
      full_path_ = FilePath();
    }
  }

  bool IsDisabled() {
    return full_path_.empty();
  }

  // Parses the OpenSearch description document at file_name (relative to
  // the data dir). The TemplateURL is placed in template_url_.
  // The result of Parse is stored in the field parse_result_ (this doesn't
  // use a return value due to internally using ASSERT_).
  void ParseFile(const std::string& file_name,
                 TemplateURLParser::ParameterFilter* filter) {
    FilePath full_path;
    parse_result_ = false;
    ASSERT_TRUE(PathService::Get(chrome::DIR_TEST_DATA, &full_path));
    full_path = full_path.AppendASCII("osdd");
    full_path = full_path.AppendASCII(file_name);
    ASSERT_TRUE(file_util::PathExists(full_path));

    std::string contents;
    ASSERT_TRUE(file_util::ReadFileToString(full_path, &contents));
    parse_result_ = TemplateURLParser::Parse(
        reinterpret_cast<const unsigned char*>(contents.c_str()),
        contents.length(), filter, &template_url_);
  }

  // ParseFile parses the results into this template_url.
  TemplateURL template_url_;

  FilePath full_path_;

  // Result of the parse.
  bool parse_result_;
};

TEST_F(TemplateURLParserTest, FailOnBogusURL) {
  if (IsDisabled())
    return;
  ParseFile("bogus.xml", NULL);
  EXPECT_FALSE(parse_result_);
}

TEST_F(TemplateURLParserTest, PassOnHTTPS) {
  if (IsDisabled())
    return;
  ParseFile("https.xml", NULL);
  EXPECT_TRUE(parse_result_);
}

TEST_F(TemplateURLParserTest, FailOnPost) {
  if (IsDisabled())
    return;
  ParseFile("post.xml", NULL);
  EXPECT_FALSE(parse_result_);
}

TEST_F(TemplateURLParserTest, TestDictionary) {
  if (IsDisabled())
    return;
  ParseFile("dictionary.xml", NULL);
  ASSERT_TRUE(parse_result_);
  EXPECT_EQ(L"Dictionary.com", template_url_.short_name());
  EXPECT_TRUE(template_url_.GetFavIconURL() ==
              GURL("http://cache.lexico.com/g/d/favicon.ico"));
  EXPECT_TRUE(template_url_.url() != NULL);
  EXPECT_TRUE(template_url_.url()->SupportsReplacement());
  EXPECT_EQ(template_url_.url()->url(),
            L"http://dictionary.reference.com/browse/{searchTerms}?r=75");
}

TEST_F(TemplateURLParserTest, TestMSDN) {
  if (IsDisabled())
    return;
  ParseFile("msdn.xml", NULL);
  ASSERT_TRUE(parse_result_);
  EXPECT_EQ(L"Search \" MSDN", template_url_.short_name());
  EXPECT_TRUE(template_url_.GetFavIconURL() ==
              GURL("http://search.msdn.microsoft.com/search/favicon.ico"));
  EXPECT_TRUE(template_url_.url() != NULL);
  EXPECT_TRUE(template_url_.url()->SupportsReplacement());
  EXPECT_EQ(template_url_.url()->url(),
            L"http://search.msdn.microsoft.com/search/default.aspx?Query={searchTerms}&brand=msdn&locale=en-US");
}

TEST_F(TemplateURLParserTest, TestWikipedia) {
  if (IsDisabled())
    return;
  ParseFile("wikipedia.xml", NULL);
  ASSERT_TRUE(parse_result_);
  EXPECT_EQ(L"Wikipedia (English)", template_url_.short_name());
  EXPECT_TRUE(template_url_.GetFavIconURL() ==
              GURL("http://en.wikipedia.org/favicon.ico"));
  EXPECT_TRUE(template_url_.url() != NULL);
  EXPECT_TRUE(template_url_.url()->SupportsReplacement());
  EXPECT_EQ(template_url_.url()->url(),
      L"http://en.wikipedia.org/w/index.php?title=Special:Search&search={searchTerms}");
  EXPECT_TRUE(template_url_.suggestions_url() != NULL);
  EXPECT_TRUE(template_url_.suggestions_url()->SupportsReplacement());
  EXPECT_EQ(template_url_.suggestions_url()->url(),
      L"http://en.wikipedia.org/w/api.php?action=opensearch&search={searchTerms}");
  ASSERT_EQ(2U, template_url_.input_encodings().size());
  EXPECT_EQ("UTF-8", template_url_.input_encodings()[0]);
  EXPECT_EQ("Shift_JIS", template_url_.input_encodings()[1]);
}

TEST_F(TemplateURLParserTest, NoCrashOnEmptyAttributes) {
  if (IsDisabled())
    return;
  ParseFile("url_with_no_attributes.xml", NULL);
}

// Filters any param which as an occurrence of name_str_ in its name or an
// occurrence of value_str_ in its value.
class ParamFilterImpl : public TemplateURLParser::ParameterFilter {
 public:
  ParamFilterImpl(std::string name_str, std::string value_str)
     : name_str_(name_str),
       value_str_(value_str) {
  }

  bool KeepParameter(const std::string& key, const std::string& value) {
    return (name_str_.empty() || key.find(name_str_) == std::string::npos) &&
           (value_str_.empty() || value.find(value_str_) == std::string::npos);
  }

 private:
  std::string name_str_;
  std::string value_str_;

  DISALLOW_EVIL_CONSTRUCTORS(ParamFilterImpl);
};

TEST_F(TemplateURLParserTest, TestFirefoxEbay) {
  if (IsDisabled())
    return;
  // This file uses the Parameter extension
  // (see http://www.opensearch.org/Specifications/OpenSearch/Extensions/Parameter/1.0)
  ParamFilterImpl filter("ebay", "ebay");
  ParseFile("firefox_ebay.xml", &filter);
  ASSERT_TRUE(parse_result_);
  EXPECT_EQ(L"eBay", template_url_.short_name());
  EXPECT_TRUE(template_url_.url() != NULL);
  EXPECT_TRUE(template_url_.url()->SupportsReplacement());
  std::wstring exp_url =
      L"http://search.ebay.com/search/search.dll?query={searchTerms}&"
      L"MfcISAPICommand=GetResult&ht=1&srchdesc=n&maxRecordsReturned=300&"
      L"maxRecordsPerPage=50&SortProperty=MetaEndSort";
  EXPECT_EQ(exp_url, template_url_.url()->url());
  ASSERT_EQ(1U, template_url_.input_encodings().size());
  EXPECT_EQ("ISO-8859-1", template_url_.input_encodings()[0]);
  EXPECT_EQ(GURL("http://search.ebay.com/favicon.ico"),
            template_url_.GetFavIconURL());
}

TEST_F(TemplateURLParserTest, TestFirefoxWebster) {
  if (IsDisabled())
    return;
  // This XML file uses a namespace.
  ParamFilterImpl filter("", "Mozilla");
  ParseFile("firefox_webster.xml", &filter);
  ASSERT_TRUE(parse_result_);
  EXPECT_EQ(L"Webster", template_url_.short_name());
  EXPECT_TRUE(template_url_.url() != NULL);
  EXPECT_TRUE(template_url_.url()->SupportsReplacement());
  EXPECT_EQ(L"http://www.webster.com/cgi-bin/dictionary?va={searchTerms}",
            template_url_.url()->url());
  ASSERT_EQ(1U, template_url_.input_encodings().size());
  EXPECT_EQ("ISO-8859-1", template_url_.input_encodings()[0]);
  EXPECT_EQ(GURL("http://www.webster.com/favicon.ico"),
            template_url_.GetFavIconURL());
}

TEST_F(TemplateURLParserTest, TestFirefoxYahoo) {
  if (IsDisabled())
    return;
  // This XML file uses a namespace.
  ParamFilterImpl filter("", "Mozilla");
  ParseFile("firefox_yahoo.xml", &filter);
  ASSERT_TRUE(parse_result_);
  EXPECT_EQ(L"Yahoo", template_url_.short_name());
  EXPECT_TRUE(template_url_.url() != NULL);
  EXPECT_TRUE(template_url_.url()->SupportsReplacement());
  EXPECT_EQ(L"http://ff.search.yahoo.com/gossip?"
            L"output=fxjson&command={searchTerms}",
            template_url_.suggestions_url()->url());
  EXPECT_EQ(L"http://search.yahoo.com/search?p={searchTerms}&ei=UTF-8",
            template_url_.url()->url());
  ASSERT_EQ(1U, template_url_.input_encodings().size());
  EXPECT_EQ("UTF-8", template_url_.input_encodings()[0]);
  EXPECT_EQ(GURL("http://search.yahoo.com/favicon.ico"),
            template_url_.GetFavIconURL());
}

// Make sure we ignore POST suggestions (this is the same XML file as
// firefox_yahoo.xml, the suggestion method was just changed to POST).
TEST_F(TemplateURLParserTest, TestPostSuggestion) {
  if (IsDisabled())
    return;
  // This XML file uses a namespace.
  ParamFilterImpl filter("", "Mozilla");
  ParseFile("post_suggestion.xml", &filter);
  ASSERT_TRUE(parse_result_);
  EXPECT_EQ(L"Yahoo", template_url_.short_name());
  EXPECT_TRUE(template_url_.url() != NULL);
  EXPECT_TRUE(template_url_.url()->SupportsReplacement());
  EXPECT_TRUE(template_url_.suggestions_url() == NULL);
  EXPECT_EQ(L"http://search.yahoo.com/search?p={searchTerms}&ei=UTF-8",
            template_url_.url()->url());
  ASSERT_EQ(1U, template_url_.input_encodings().size());
  EXPECT_EQ("UTF-8", template_url_.input_encodings()[0]);
  EXPECT_EQ(GURL("http://search.yahoo.com/favicon.ico"),
            template_url_.GetFavIconURL());
}
<|endoftext|>