<commit_before>/***********************************************************************
    created:    Tue Feb 17 2009
    author:     Paul D Turner
*************************************************************************/
/***************************************************************************
 *   Copyright (C) 2004 - 2013 Paul D Turner & The CEGUI Development Team
 *
 *   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 BE LIABLE FOR ANY CLAIM, DAMAGES OR
 *   OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
 *   ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
 *   OTHER DEALINGS IN THE SOFTWARE.
 ***************************************************************************/
#include "CEGUI/RendererModules/Ogre/RenderTarget.h"
#include "CEGUI/GeometryBuffer.h"
#include "CEGUI/RenderQueue.h"
#include "CEGUI/RendererModules/Ogre/GeometryBuffer.h"

#include <OgreRenderSystem.h>
#include <OgreCamera.h>
#include <OgreViewport.h>

#include <glm/glm.hpp>
#include <glm/gtc/type_ptr.hpp>
#include <glm/gtc/matrix_transform.hpp>

// Start of CEGUI namespace section
namespace CEGUI
{

//----------------------------------------------------------------------------//
template <typename T>
const float OgreRenderTarget<T>::d_yfov_tan = 0.267949192431123f;

//----------------------------------------------------------------------------//
template <typename T>
OgreRenderTarget<T>::OgreRenderTarget(OgreRenderer& owner,
                                      Ogre::RenderSystem& rs) :
    d_owner(owner),
    d_renderSystem(rs),
    d_area(0, 0, 0, 0),
    d_renderTarget(0),
    d_viewport(0),
    d_ogreViewportDimensions(0, 0, 0, 0),
    d_matrix(Ogre::Matrix4::IDENTITY),
    d_matrixValid(false),
    d_viewportValid(false),
    d_viewDistance(0)
{
}

//----------------------------------------------------------------------------//
template <typename T>
OgreRenderTarget<T>::~OgreRenderTarget()
{
    delete d_viewport;
}

//----------------------------------------------------------------------------//
template <typename T>
void OgreRenderTarget<T>::draw(const GeometryBuffer& buffer)
{
    buffer.draw();
}

//----------------------------------------------------------------------------//
template <typename T>
void OgreRenderTarget<T>::draw(const RenderQueue& queue)
{
    queue.draw();
}

//----------------------------------------------------------------------------//
template <typename T>
void OgreRenderTarget<T>::setArea(const Rectf& area)
{
    d_area = area;
    setOgreViewportDimensions(area);

    d_matrixValid = false;

    RenderTargetEventArgs args(this);
    T::fireEvent(RenderTarget::EventAreaChanged, args);
}

//----------------------------------------------------------------------------//
template <typename T>
void OgreRenderTarget<T>::setOgreViewportDimensions(const Rectf& area)
{
    d_ogreViewportDimensions = area;

    if (d_viewport)
        updateOgreViewportDimensions(d_viewport->getTarget());

    d_viewportValid = false;
}

//----------------------------------------------------------------------------//
template <typename T>
void OgreRenderTarget<T>::updateOgreViewportDimensions(
                                            const Ogre::RenderTarget* const rt)
{
    if (rt)
    {
        if(d_viewport)
            d_viewport->setDimensions(
            d_ogreViewportDimensions.left() / rt->getWidth(),
            d_ogreViewportDimensions.top() / rt->getHeight(),
            d_ogreViewportDimensions.getWidth() / rt->getWidth(),
            d_ogreViewportDimensions.getHeight() / rt->getHeight());
    }
}

//----------------------------------------------------------------------------//
template <typename T>
const Rectf& OgreRenderTarget<T>::getArea() const
{
    return d_area;
}

//----------------------------------------------------------------------------//
template <typename T>
void OgreRenderTarget<T>::activate()
{
    if (!d_matrixValid)
        updateMatrix();

    if (!d_viewportValid)
        updateViewport();

    d_renderSystem._setViewport(d_viewport);

    d_owner.setProjectionMatrix(d_matrix);

    RenderTarget::activate();
}

//----------------------------------------------------------------------------//
template <typename T>
void OgreRenderTarget<T>::deactivate()
{
    // currently nothing to do in the basic case
}

//----------------------------------------------------------------------------//
template <typename T>
void OgreRenderTarget<T>::unprojectPoint(const GeometryBuffer& buff,
                                         const glm::vec2& p_in,
                                         glm::vec2& p_out) const
{
    if (!d_matrixValid)
        updateMatrix();

    const OgreGeometryBuffer& gb = static_cast<const OgreGeometryBuffer&>(buff);

    const Ogre::Real midx = d_area.getWidth() * 0.5f;
    const Ogre::Real midy = d_area.getHeight() * 0.5f;

    // viewport matrix
    const Ogre::Matrix4 vpmat(
        midx,    0,    0,    d_area.left() + midx,
         0,    -midy,  0,    d_area.top() + midy,
         0,      0,    1,    0,
         0,      0,    0,    1
    );

    // matrices used for projecting and unprojecting points

    const Ogre::Matrix4 proj(OgreRenderer::glmToOgreMatrix(gb.getModelMatrix()) * d_matrix * vpmat);
    const Ogre::Matrix4 unproj(proj.inverse());

    Ogre::Vector3 in;

    // unproject the ends of the ray
    in.x = midx;
    in.y = midy;
    in.z = -d_viewDistance;
    const Ogre::Vector3 r1(unproj * in);
    in.x = p_in.x;
    in.y = p_in.y;
    in.z = 0;
    // calculate vector of picking ray
    const Ogre::Vector3 rv(r1 - unproj * in);

    // project points to orientate them with GeometryBuffer plane
    in.x = 0.0;
    in.y = 0.0;
    const Ogre::Vector3 p1(proj * in);
    in.x = 1.0;
    in.y = 0.0;
    const Ogre::Vector3 p2(proj * in);
    in.x = 0.0;
    in.y = 1.0;
    const Ogre::Vector3 p3(proj * in);

    // calculate the plane normal
    const Ogre::Vector3 pn((p2 - p1).crossProduct(p3 - p1));
    // calculate distance from origin
    const Ogre::Real plen = pn.length();
    const Ogre::Real dist = -(p1.x * (pn.x / plen) +
                              p1.y * (pn.y / plen) +
                              p1.z * (pn.z / plen));

    // calculate intersection of ray and plane
    const Ogre::Real pn_dot_rv = pn.dotProduct(rv);
    const Ogre::Real tmp = pn_dot_rv != 0.0 ?
                            (pn.dotProduct(r1) + dist) / pn_dot_rv :
                            0.0f;

    p_out.x = static_cast<float>(r1.x - rv.x * tmp);
    p_out.y = static_cast<float>(r1.y - rv.y * tmp);
}

//----------------------------------------------------------------------------//
template <typename T>
void OgreRenderTarget<T>::updateMatrix() const
{
    const float w = d_area.getWidth();
    const float h = d_area.getHeight();

    // We need to check if width or height are zero and act accordingly to prevent running into issues
    // with divisions by zero which would lead to undefined values, as well as faulty clipping planes
    // This is mostly important for avoiding asserts
    const bool widthAndHeightNotZero = ( w != 0.0f ) && ( h != 0.0f);

    const float aspect = widthAndHeightNotZero ? w / h : 1.0f;
    const float midx = widthAndHeightNotZero ? w * 0.5f : 0.5f;
    const float midy = widthAndHeightNotZero ? h * 0.5f : 0.5f;
    d_viewDistance = midx / (aspect * d_yfov_tan);

    glm::vec3 eye = glm::vec3(midx, midy, -d_viewDistance);
    glm::vec3 center = glm::vec3(midx, midy, 1);
    glm::vec3 up = glm::vec3(0, -1, 0);

    glm::mat4 projectionMatrix = glm::perspective(30.f, aspect, d_viewDistance * 0.5f, d_viewDistance * 2.0f);
    // Projection matrix abuse!
    glm::mat4 viewMatrix = glm::lookAt(eye, center, up);

    glm::mat4 finalMatrix = projectionMatrix * viewMatrix;

    Ogre::Matrix4 temp = OgreRenderer::glmToOgreMatrix(finalMatrix);
    d_renderSystem._convertProjectionMatrix(temp, d_matrix, true);

    d_matrixValid = true;
    //! This will trigger the RenderTarget to notify all of its GeometryBuffers to regenerate their matrices
    RenderTarget::d_activationCounter = -1;
}

//----------------------------------------------------------------------------//
template <typename T>
void OgreRenderTarget<T>::updateViewport()
{
    if (!d_viewport)
    {
#ifdef CEGUI_USE_OGRE_COMPOSITOR2

        d_viewport = OGRE_NEW Ogre::Viewport(d_renderTarget, 0, 0, 1, 1);
#else
        d_viewport = OGRE_NEW Ogre::Viewport(0, d_renderTarget, 0, 0, 1, 1, 0);
#endif // CEGUI_USE_OGRE_COMPOSITOR2

        updateOgreViewportDimensions(d_renderTarget);
    }

    d_viewport->_updateDimensions();

    d_viewportValid = true;
}

//----------------------------------------------------------------------------//
template <typename T>
Renderer& OgreRenderTarget<T>::getOwner()
{
    return d_owner;
}

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

} // End of  CEGUI namespace section
<commit_msg>MOD: Removing matrix conversion<commit_after>/***********************************************************************
    created:    Tue Feb 17 2009
    author:     Paul D Turner
*************************************************************************/
/***************************************************************************
 *   Copyright (C) 2004 - 2013 Paul D Turner & The CEGUI Development Team
 *
 *   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 BE LIABLE FOR ANY CLAIM, DAMAGES OR
 *   OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
 *   ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
 *   OTHER DEALINGS IN THE SOFTWARE.
 ***************************************************************************/
#include "CEGUI/RendererModules/Ogre/RenderTarget.h"
#include "CEGUI/GeometryBuffer.h"
#include "CEGUI/RenderQueue.h"
#include "CEGUI/RendererModules/Ogre/GeometryBuffer.h"

#include <OgreRenderSystem.h>
#include <OgreCamera.h>
#include <OgreViewport.h>

#include <glm/glm.hpp>
#include <glm/gtc/type_ptr.hpp>
#include <glm/gtc/matrix_transform.hpp>

// Start of CEGUI namespace section
namespace CEGUI
{

//----------------------------------------------------------------------------//
template <typename T>
const float OgreRenderTarget<T>::d_yfov_tan = 0.267949192431123f;

//----------------------------------------------------------------------------//
template <typename T>
OgreRenderTarget<T>::OgreRenderTarget(OgreRenderer& owner,
                                      Ogre::RenderSystem& rs) :
    d_owner(owner),
    d_renderSystem(rs),
    d_area(0, 0, 0, 0),
    d_renderTarget(0),
    d_viewport(0),
    d_ogreViewportDimensions(0, 0, 0, 0),
    d_matrix(Ogre::Matrix4::IDENTITY),
    d_matrixValid(false),
    d_viewportValid(false),
    d_viewDistance(0)
{
}

//----------------------------------------------------------------------------//
template <typename T>
OgreRenderTarget<T>::~OgreRenderTarget()
{
    delete d_viewport;
}

//----------------------------------------------------------------------------//
template <typename T>
void OgreRenderTarget<T>::draw(const GeometryBuffer& buffer)
{
    buffer.draw();
}

//----------------------------------------------------------------------------//
template <typename T>
void OgreRenderTarget<T>::draw(const RenderQueue& queue)
{
    queue.draw();
}

//----------------------------------------------------------------------------//
template <typename T>
void OgreRenderTarget<T>::setArea(const Rectf& area)
{
    d_area = area;
    setOgreViewportDimensions(area);

    d_matrixValid = false;

    RenderTargetEventArgs args(this);
    T::fireEvent(RenderTarget::EventAreaChanged, args);
}

//----------------------------------------------------------------------------//
template <typename T>
void OgreRenderTarget<T>::setOgreViewportDimensions(const Rectf& area)
{
    d_ogreViewportDimensions = area;

    if (d_viewport)
        updateOgreViewportDimensions(d_viewport->getTarget());

    d_viewportValid = false;
}

//----------------------------------------------------------------------------//
template <typename T>
void OgreRenderTarget<T>::updateOgreViewportDimensions(
                                            const Ogre::RenderTarget* const rt)
{
    if (rt)
    {
        if(d_viewport)
            d_viewport->setDimensions(
            d_ogreViewportDimensions.left() / rt->getWidth(),
            d_ogreViewportDimensions.top() / rt->getHeight(),
            d_ogreViewportDimensions.getWidth() / rt->getWidth(),
            d_ogreViewportDimensions.getHeight() / rt->getHeight());
    }
}

//----------------------------------------------------------------------------//
template <typename T>
const Rectf& OgreRenderTarget<T>::getArea() const
{
    return d_area;
}

//----------------------------------------------------------------------------//
template <typename T>
void OgreRenderTarget<T>::activate()
{
    if (!d_matrixValid)
        updateMatrix();

    if (!d_viewportValid)
        updateViewport();

    d_renderSystem._setViewport(d_viewport);

    d_owner.setProjectionMatrix(d_matrix);

    RenderTarget::activate();
}

//----------------------------------------------------------------------------//
template <typename T>
void OgreRenderTarget<T>::deactivate()
{
    // currently nothing to do in the basic case
}

//----------------------------------------------------------------------------//
template <typename T>
void OgreRenderTarget<T>::unprojectPoint(const GeometryBuffer& buff,
                                         const glm::vec2& p_in,
                                         glm::vec2& p_out) const
{
    if (!d_matrixValid)
        updateMatrix();

    const OgreGeometryBuffer& gb = static_cast<const OgreGeometryBuffer&>(buff);

    const Ogre::Real midx = d_area.getWidth() * 0.5f;
    const Ogre::Real midy = d_area.getHeight() * 0.5f;

    // viewport matrix
    const Ogre::Matrix4 vpmat(
        midx,    0,    0,    d_area.left() + midx,
         0,    -midy,  0,    d_area.top() + midy,
         0,      0,    1,    0,
         0,      0,    0,    1
    );

    // matrices used for projecting and unprojecting points

    const Ogre::Matrix4 proj(OgreRenderer::glmToOgreMatrix(gb.getModelMatrix()) * d_matrix * vpmat);
    const Ogre::Matrix4 unproj(proj.inverse());

    Ogre::Vector3 in;

    // unproject the ends of the ray
    in.x = midx;
    in.y = midy;
    in.z = -d_viewDistance;
    const Ogre::Vector3 r1(unproj * in);
    in.x = p_in.x;
    in.y = p_in.y;
    in.z = 0;
    // calculate vector of picking ray
    const Ogre::Vector3 rv(r1 - unproj * in);

    // project points to orientate them with GeometryBuffer plane
    in.x = 0.0;
    in.y = 0.0;
    const Ogre::Vector3 p1(proj * in);
    in.x = 1.0;
    in.y = 0.0;
    const Ogre::Vector3 p2(proj * in);
    in.x = 0.0;
    in.y = 1.0;
    const Ogre::Vector3 p3(proj * in);

    // calculate the plane normal
    const Ogre::Vector3 pn((p2 - p1).crossProduct(p3 - p1));
    // calculate distance from origin
    const Ogre::Real plen = pn.length();
    const Ogre::Real dist = -(p1.x * (pn.x / plen) +
                              p1.y * (pn.y / plen) +
                              p1.z * (pn.z / plen));

    // calculate intersection of ray and plane
    const Ogre::Real pn_dot_rv = pn.dotProduct(rv);
    const Ogre::Real tmp = pn_dot_rv != 0.0 ?
                            (pn.dotProduct(r1) + dist) / pn_dot_rv :
                            0.0f;

    p_out.x = static_cast<float>(r1.x - rv.x * tmp);
    p_out.y = static_cast<float>(r1.y - rv.y * tmp);
}

//----------------------------------------------------------------------------//
template <typename T>
void OgreRenderTarget<T>::updateMatrix() const
{
    const float w = d_area.getWidth();
    const float h = d_area.getHeight();

    // We need to check if width or height are zero and act accordingly to prevent running into issues
    // with divisions by zero which would lead to undefined values, as well as faulty clipping planes
    // This is mostly important for avoiding asserts
    const bool widthAndHeightNotZero = ( w != 0.0f ) && ( h != 0.0f);

    const float aspect = widthAndHeightNotZero ? w / h : 1.0f;
    const float midx = widthAndHeightNotZero ? w * 0.5f : 0.5f;
    const float midy = widthAndHeightNotZero ? h * 0.5f : 0.5f;
    d_viewDistance = midx / (aspect * d_yfov_tan);

    glm::vec3 eye = glm::vec3(midx, midy, -d_viewDistance);
    glm::vec3 center = glm::vec3(midx, midy, 1);
    glm::vec3 up = glm::vec3(0, -1, 0);

    glm::mat4 projectionMatrix = glm::perspective(30.f, aspect, d_viewDistance * 0.5f, d_viewDistance * 2.0f);
    // Projection matrix abuse!
    glm::mat4 viewMatrix = glm::lookAt(eye, center, up);

    glm::mat4 finalMatrix = projectionMatrix * viewMatrix;

    d_matrix = OgreRenderer::glmToOgreMatrix(finalMatrix);

    d_matrixValid = true;
    //! This will trigger the RenderTarget to notify all of its GeometryBuffers to regenerate their matrices
    RenderTarget::d_activationCounter = -1;
}

//----------------------------------------------------------------------------//
template <typename T>
void OgreRenderTarget<T>::updateViewport()
{
    if (!d_viewport)
    {
#ifdef CEGUI_USE_OGRE_COMPOSITOR2

        d_viewport = OGRE_NEW Ogre::Viewport(d_renderTarget, 0, 0, 1, 1);
#else
        d_viewport = OGRE_NEW Ogre::Viewport(0, d_renderTarget, 0, 0, 1, 1, 0);
#endif // CEGUI_USE_OGRE_COMPOSITOR2

        updateOgreViewportDimensions(d_renderTarget);
    }

    d_viewport->_updateDimensions();

    d_viewportValid = true;
}

//----------------------------------------------------------------------------//
template <typename T>
Renderer& OgreRenderTarget<T>::getOwner()
{
    return d_owner;
}

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

} // End of  CEGUI namespace section
<|endoftext|>


<commit_before>#include "RedBlackTree.h"
#include <algorithm>
#include <cassert>
#include <utility>

#define RED 'R'
#define BLACK 'B'

RbNode RBNIL = {BLACK, -1, &RBNIL, &RBNIL, &RBNIL};

#define is_nil(e) ((e) == &RBNIL)
#define not_nil(e) ((e) != &RBNIL)
#define set_nil(e) ((e) = &RBNIL)
#define is_leaf(e) (is_nil((e)->left) && is_nil((e)->right))

static RbNode *Previous(RbNode *e) {
  while (not_nil(e->left))
    e = e->left;
  return e;
}

static RbNode *Next(RbNode *e) {
  if (is_nil(e->right)) {
    return &RBNIL;
  }
  RbNode *next = e->right;
  while (not_nil(next->left)) {
    next = next->left;
  }
  return next;
}

static RbNode *GrandFather(RbNode *e) {
  if (is_nil(e))
    return &RBNIL;
  if (is_nil(e->father))
    return &RBNIL;
  return e->father->father;
}

static RbNode *Uncle(RbNode *e) {
  if (is_nil(GrandFather(e)))
    return &RBNIL;
  if (GrandFather(e)->left == e)
    return GrandFather(e)->right;
  if (GrandFather(e)->right == e)
    return GrandFather(e)->left;
  return &RBNIL;
}

static bool IsLeft(RbNode *e) {
  if (is_nil(e->father))
    return false;
  return e->father->left == e;
}

static bool IsRight(RbNode *e) {
  if (is_nil(e->father))
    return false;
  return e->father->right == e;
}

static int ChildNumber(RbNode *e) {
  return is_nil(e) ? 0
                   : ((is_nil(e->left) ? 0 : 1) + (is_nil(e->right) ? 0 : 1));
}

static RbNode *Brother(RbNode *e) {
  if (is_nil(e))
    return &RBNIL;
  if (IsLeft(e)) {
    return e->father->right;
  }
  if (IsRight(e)) {
    return e->father->left;
  }
  return &RBNIL;
}

static void Free(RbNode *e) {
  if (is_nil(e))
    return;
  Free(e->left);
  Free(e->right);
  delete e;
}

static void LeftRotate(RbNode *&father, RbNode *&e) {
  RbNode *p_right = e->right;
  e->right = p_right->left;

  if (not_nil(e->right)) {
    e->right->father = e;
  }

  p_right->father = e->father;

  if (is_nil(e->father)) {
    father = p_right;
  } else if (e == e->father->left) {
    e->father->left = p_right;
  } else {
    e->father->right = p_right;
  }

  p_right->left = e;
  e->father = p_right;
}

static void RightRotate(RbNode *&father, RbNode *&e) {
  RbNode *p_left = e->left;
  e->left = p_left->right;

  if (not_nil(e->left)) {
    e->left->father = e;
  }

  p_left->father = e->father;

  if (is_nil(e->father)) {
    father = p_left;
  } else if (e == e->father->left) {
    e->father->left = p_left;
  } else {
    e->father->right = p_left;
  }

  p_left->right = e;
  e->father = p_left;
}

void FixInsert(RbNode *&root, RbNode *&e) {
  RbNode *e_father = &RBNIL;
  RbNode *e_grand_father = &RBNIL;

  while ((e != root) && (e->color != BLACK) && (e->father->color == RED)) {
    e_father = e->father;
    e_grand_father = e->father->father;

    // case A
    if (e_father == e_grand_father->left) {
      RbNode *e_uncle = e_grand_father->right;

      // case 1: Red Uncle
      if (not_nil(e_uncle) && e_uncle->color == RED) {
        e_grand_father->color = RED;
        e_father->color = BLACK;
        e_uncle->color = BLACK;
        e = e_grand_father;
      } else {

        // case 2: Black Uncle, left-right-case
        if (e == e_father->right) {
          LeftRotate(root, e_father);
          e = e_father;
          e_father = e->father;
        }

        // case 3: Black Uncle, left-left-case
        RightRotate(root, e_grand_father);
        std::swap(e_father->color, e_grand_father->color);
        e = e_father;
      }
    }

    // case B
    else {
      RbNode *e_uncle = e_grand_father->right;

      // case 1: Red Uncle
      if (not_nil(e_uncle) && (e_uncle->color == RED)) {
        e_grand_father->color = RED;
        e_father->color = BLACK;
        e_uncle->color = BLACK;
        e = e_grand_father;
      } else {

        // case 4: Black Uncle, left-right-case
        if (e == e_father->left) {
          RightRotate(root, e_father);
          e = e_father;
          e_father = e->father;
        }

        // case 5: Black Uncle, right-right-case
        LeftRotate(root, e_grand_father);
        std::swap(e_father->color, e_grand_father->color);
        e = e_father;
      }
    }
  } // while

  root->color = BLACK;
} // FixInsert

static RbNode *Replace(RbNode *e) {
  if (not_nil(e->left) && not_nil(e->right)) {
    return Previous(e->right);
  }
  if (is_nil(e->left) && is_nil(e->right)) {
    return &RBNIL;
  }
  if (not_nil(e->left)) {
    return e->left;
  } else {
    return e->right;
  }
}

static void FixErase(RbNode *&root, RbNode *&e) {
  if (e == root) {
    e->color = BLACK;
    return;
  }

  RbNode *e_father = e->father;
  RbNode *e_grand_father = e_father->father;
  RbNode *e_uncle = Uncle(e);

  if (e_father->color != BLACK) {
    if (not_nil(e_uncle) && e_uncle->color == RED) {
      e_father->color = BLACK;
      e_uncle->color = BLACK;
      e_grand_father->color = RED;
      e_grand_father->color = RED;
    }
  }
}

static void Erase(RbNode *&root, RbNode *&e) {
  RbNode *p = Replace(e);
  bool pe_black = ((is_nil(p) || p->color == BLACK) && (e->color == BLACK));
  RbNode *e_father = e->father;

  if (is_nil(p)) {
    if (e == root) {
      set_nil(root);
    } else {
      if (pe_black) {
        FixErase(root, e);
      } else {
        if (not_nil(Uncle(e))) {
          Uncle(e)->color = RED;
        }
      }
      if (IsLeft(e)) {
        set_nil(e_father->left);
      } else {
        set_nil(e_father->right);
      }
    }

    delete e;
    return;
  } // if (is_nil(p))

  if (is_nil(e->left) || is_nil(e->right)) {
    if (e == root) {
      e->value = p->value;
      set_nil(e->left);
      set_nil(e->right);
      delete p;
    } else {
      if (IsLeft(e)) {
        e_father->left = p;
      } else {
        e_father->right = p;
      }
      delete e;
      p->father = e_father;
      if (pe_black) {
        FixErase(root, e);
      } else {
        p->color = BLACK;
      }
    }
    return;
  } // if (is_nil(e->left) || is_nil(e->right))

  std::swap(p->color, e->color);
  Erase(root, e);
} // Erase

static RbNode *Find(RbNode *e, int value) {
  if (is_nil(e)) {
    return &RBNIL;
  }
  //二分查找
  if (e->value == value) {
    return e;
  } else if (e->value > value) {
    return Find(e->left, value);
  } else {
    return Find(e->right, value);
  }
}

static RbNode *Insert(RbNode *father, RbNode *e) {
  assert(father);
  assert(e);

  if (is_nil(father)) {
    return e;
  }

  //利用二分查找找到适合value插入的位置e

  if (father->value > e->value) {
    father->left = Insert(father->left, e);
    father->left->father = father;
  } else if (father->value < e->value) {
    father->right = Insert(father->right, e);
    father->right->father = father;
  } else {
    assert(father->value != e->value);
  }
  return father;
}

RedBlackTree *RedBlackTreeNew() {
  RedBlackTree *t = new RedBlackTree();
  if (!t)
    return NULL;
  t->root = &RBNIL;
  return t;
}

void RedBlackTreeFree(RedBlackTree *t) {
  assert(t);
  Free(t->root);
  delete t;
}

void RedBlackTreeInsert(RedBlackTree *t, int value) {
  assert(t);
  assert(value >= 0);

  RbNode *e = new RbNode();
  set_nil(e->left);
  set_nil(e->right);
  set_nil(e->father);
  e->color = RED; // new node is red
  e->value = value;

  t->root = Insert(t->root, e);
  FixInsert(t->root, e);
}

RbNode *RedBlackTreeFind(RedBlackTree *t, int value) {
  return Find(t->root, value);
}

void RedBlackTreeErase(RedBlackTree *t, int value) {
  RbNode *e = Find(t->root, value);
  if (is_nil(e)) {
    return;
  }
  Erase(t->root, e);
}

<commit_msg>save code<commit_after>#include "RedBlackTree.h"
#include <algorithm>
#include <cassert>
#include <utility>

#define RED 'R'
#define BLACK 'B'

RbNode RBNIL = {BLACK, -1, &RBNIL, &RBNIL, &RBNIL};

#define is_nil(e) ((e) == &RBNIL)
#define not_nil(e) ((e) != &RBNIL)
#define set_nil(e) ((e) = &RBNIL)
#define is_leaf(e) (is_nil((e)->left) && is_nil((e)->right))

static RbNode *Next(RbNode *e) {
  if (is_nil(e->right)) {
    return &RBNIL;
  }
  RbNode *next = e->right;
  while (not_nil(next->left)) {
    next = next->left;
  }
  return next;
}

static RbNode *GrandFather(RbNode *e) {
  if (is_nil(e))
    return &RBNIL;
  if (is_nil(e->father))
    return &RBNIL;
  return e->father->father;
}

static RbNode *Uncle(RbNode *e) {
  if (is_nil(GrandFather(e)))
    return &RBNIL;
  if (GrandFather(e)->left == e)
    return GrandFather(e)->right;
  if (GrandFather(e)->right == e)
    return GrandFather(e)->left;
  return &RBNIL;
}

static bool IsLeft(RbNode *e) {
  if (is_nil(e->father))
    return false;
  return e->father->left == e;
}

static bool IsRight(RbNode *e) {
  if (is_nil(e->father))
    return false;
  return e->father->right == e;
}

static RbNode *Brother(RbNode *e) {
  if (is_nil(e))
    return &RBNIL;
  if (IsLeft(e)) {
    return e->father->right;
  }
  if (IsRight(e)) {
    return e->father->left;
  }
  return &RBNIL;
}

static void Free(RbNode *e) {
  if (is_nil(e))
    return;
  Free(e->left);
  Free(e->right);
  delete e;
}

static void LeftRotate(RbNode *&father, RbNode *&e) {
  RbNode *p_right = e->right;
  e->right = p_right->left;

  if (not_nil(e->right)) {
    e->right->father = e;
  }

  p_right->father = e->father;

  if (is_nil(e->father)) {
    father = p_right;
  } else if (e == e->father->left) {
    e->father->left = p_right;
  } else {
    e->father->right = p_right;
  }

  p_right->left = e;
  e->father = p_right;
}

static void RightRotate(RbNode *&father, RbNode *&e) {
  RbNode *p_left = e->left;
  e->left = p_left->right;

  if (not_nil(e->left)) {
    e->left->father = e;
  }

  p_left->father = e->father;

  if (is_nil(e->father)) {
    father = p_left;
  } else if (e == e->father->left) {
    e->father->left = p_left;
  } else {
    e->father->right = p_left;
  }

  p_left->right = e;
  e->father = p_left;
}

void FixInsert(RbNode *&root, RbNode *&e) {
  RbNode *e_father, *e_grand_father;
  set_nil(e_father);
  set_nil(e_grand_father);

  while ((e != root) && (e->color != BLACK) && (e->father->color == RED)) {
    e_father = e->father;
    e_grand_father = e->father->father;

    // case A
    if (e_father == e_grand_father->left) {
      RbNode *e_uncle = e_grand_father->right;

      // case 1: Red Uncle
      if (not_nil(e_uncle) && e_uncle->color == RED) {
        e_grand_father->color = RED;
        e_father->color = BLACK;
        e_uncle->color = BLACK;
        e = e_grand_father;
      } else {

        // case 2: Black Uncle, left-right-case
        if (e == e_father->right) {
          LeftRotate(root, e_father);
          e = e_father;
          e_father = e->father;
        }

        // case 3: Black Uncle, left-left-case
        RightRotate(root, e_grand_father);
        std::swap(e_father->color, e_grand_father->color);
        e = e_father;
      }
    }

    // case B
    else {
      RbNode *e_uncle = e_grand_father->right;

      // case 1: Red Uncle
      if (not_nil(e_uncle) && (e_uncle->color == RED)) {
        e_grand_father->color = RED;
        e_father->color = BLACK;
        e_uncle->color = BLACK;
        e = e_grand_father;
      } else {

        // case 4: Black Uncle, left-right-case
        if (e == e_father->left) {
          RightRotate(root, e_father);
          e = e_father;
          e_father = e->father;
        }

        // case 5: Black Uncle, right-right-case
        LeftRotate(root, e_grand_father);
        std::swap(e_father->color, e_grand_father->color);
        e = e_father;
      }
    }
  } // while

  root->color = BLACK;
} // FixInsert

static RbNode *Replace(RbNode *e) {
  if (not_nil(e->left) && not_nil(e->right)) {
    return Next(e->right);
  }
  if (is_nil(e->left) && is_nil(e->right)) {
    return &RBNIL;
  }
  if (not_nil(e->left)) {
    return e->left;
  } else {
    return e->right;
  }
}

static void FixErase(RbNode *&root, RbNode *&e) {
  // reach root
  if (e == root) {
    return;
  }

  RbNode *e_brother = &RBNIL;
  RbNode *e_father = &RBNIL;

  while (true) {
    e_brother = Brother(e);
    e_father = e->father;

    RbNode *e_brother = Brother(e);
    RbNode *e_father = e->father;

    if (is_nil(e_brother)) {
      // no brother
      // double black pushed up
      FixErase(root, e_father);

    } else {
      if (e_brother->color == RED) {
        // brother red
        e_father->color = RED;
        e_brother->color = BLACK;
        if (IsLeft(e_brother)) {
          // left case
          RightRotate(root, e_father);
        } else {
          // right case
          LeftRotate(root, e_father);
        }
        FixErase(root, e);
      } else {
        // brother black
        if (e_brother->left->color == RED || e_brother->right->color == RED) {
          // at least 1 red children
          if (not_nil(e_brother->left) && e_brother->left->color == RED) {
            if (IsLeft(e_brother)) {
              // left left
              e_brother->left->color = e_brother->color;
              e_brother->color = e_father->color;
              RightRotate(root, e_father);
            } else {
              // right left
              e_brother->left->color = e_father->color;
              RightRotate(root, e_brother);
              LeftRotate(root, e_father);
            }
          } else {
            if (IsLeft(e_brother)) {
              // left right
              e_brother->right->color = e_father->color;
              LeftRotate(root, e_brother);
              RightRotate(root, e_father);
            } else {
              // right right
              e_brother->right->color = e_brother->color;
              e_brother->color = e_father->color;
              LeftRotate(root, e_father);
            }
          }
          e_father->color = BLACK;
        } else {
          // 2 black children
          e_brother->color = RED;
          if (e_father->color == BLACK) {
            FixErase(root, e_father);
          } else {
            e_father->color = BLACK;
          }
        }
      }
    }
  } // while
} // FixErase

static void Erase(RbNode *&root, RbNode *&e) {
  RbNode *p = Replace(e);
  bool pe_black = ((is_nil(p) || p->color == BLACK) && (e->color == BLACK));
  RbNode *e_father = e->father;

  if (is_nil(p)) {
    if (e == root) {
      set_nil(root);
    } else {
      if (pe_black) {
        FixErase(root, e);
      } else {
        if (not_nil(Uncle(e))) {
          Uncle(e)->color = RED;
        }
      }
      if (IsLeft(e)) {
        set_nil(e_father->left);
      } else {
        set_nil(e_father->right);
      }
    }

    delete e;
    return;
  } // if (is_nil(p))

  if (is_nil(e->left) || is_nil(e->right)) {
    if (e == root) {
      e->value = p->value;
      set_nil(e->left);
      set_nil(e->right);
      delete p;
    } else {
      if (IsLeft(e)) {
        e_father->left = p;
      } else {
        e_father->right = p;
      }
      delete e;
      p->father = e_father;
      if (pe_black) {
        FixErase(root, e);
      } else {
        p->color = BLACK;
      }
    }
    return;
  } // if (is_nil(e->left) || is_nil(e->right))

  std::swap(p->color, e->color);
  Erase(root, e);
} // Erase

static RbNode *Find(RbNode *e, int value) {
  if (is_nil(e)) {
    return &RBNIL;
  }
  //二分查找
  if (e->value == value) {
    return e;
  } else if (e->value > value) {
    return Find(e->left, value);
  } else {
    return Find(e->right, value);
  }
}

static RbNode *Insert(RbNode *father, RbNode *e) {
  assert(father);
  assert(e);

  if (is_nil(father)) {
    return e;
  }

  //利用二分查找找到适合value插入的位置e

  if (father->value > e->value) {
    father->left = Insert(father->left, e);
    father->left->father = father;
  } else if (father->value < e->value) {
    father->right = Insert(father->right, e);
    father->right->father = father;
  } else {
    assert(father->value != e->value);
  }
  return father;
}

RedBlackTree *RedBlackTreeNew() {
  RedBlackTree *t = new RedBlackTree();
  if (!t)
    return NULL;
  t->root = &RBNIL;
  return t;
}

void RedBlackTreeFree(RedBlackTree *t) {
  assert(t);
  Free(t->root);
  delete t;
}

void RedBlackTreeInsert(RedBlackTree *t, int value) {
  assert(t);
  assert(value >= 0);

  RbNode *e = new RbNode();
  set_nil(e->left);
  set_nil(e->right);
  set_nil(e->father);
  e->color = RED; // new node is red
  e->value = value;

  t->root = Insert(t->root, e);
  FixInsert(t->root, e);
}

RbNode *RedBlackTreeFind(RedBlackTree *t, int value) {
  return Find(t->root, value);
}

void RedBlackTreeErase(RedBlackTree *t, int value) {
  RbNode *e = Find(t->root, value);
  if (is_nil(e)) {
    return;
  }
  Erase(t->root, e);
}

<|endoftext|>


<commit_before>#include "GolfBall.hpp"
#include "../Resources.hpp"
#include "Default3D.vert.hpp"
#include "Default3D.geom.hpp"
#include "Default3D.frag.hpp"
#include "glm\gtc\constants.hpp"

GolfBall::GolfBall(BallType ballType) : Object() {
    active = false;

	modelGeometry = new Geometry::Model("Resources/Models/rock/Rock.bin");
	std::string diffusePath = "Resources/Models/rock/diffuse.tga";
	std::string normalPath = "Resources/Models/rock/normal.tga";
	std::string specularPath = "Resources/Models/rock/specular.tga";
	modelObject = new ModelObject(modelGeometry, diffusePath, normalPath, specularPath);
	modelObject->SetPosition(2.f, 0.f, 0.f);
	modelObject->SetScale(glm::vec3(0.01f, 0.01f, 0.01f));

    /// @todo Mass based on explosive material.
    mass = 0.0459f;
    this->ballType = ballType;

    SetRadius(0.0214f);
}

GolfBall::~GolfBall() {
	delete modelObject;
	delete modelGeometry;
}

void GolfBall::Update(double time, const glm::vec3& wind) {
    if (active) {
		modelObject->Move(static_cast<float>(time)* velocity);
		float horizontal = static_cast<float>(time)*angularVelocity.x;
		float vertical = static_cast<float>(time)*angularVelocity.y;
		float tilt = static_cast<float>(time)*angularVelocity.z;

		modelObject->Rotate(horizontal, vertical, tilt);

        float v = velocity.length();
		float w = angularVelocity.length();
        float u = (velocity - wind).length();
		float Cm = (sqrt(1.f + 0.31f*(v/w))-1.f)/20.f;
		float Fm = 0.5f*Cm*1.23*area*u*u;

        glm::vec3 eU = (velocity - wind) / u;

        /// Calculate drive force.
        float cD;
        if (ballType == TWOPIECE) {
            cD = v < 65.f ? -0.0051f * v + 0.53f : 0.21f;
        } else {
            cD = v < 60.f ? -0.0084f * v + 0.73f : 0.22f;
        }
        glm::vec3 driveForce = -0.5f * 1.23f * area * cD * u * u * eU;

		glm::vec3 magnusForce = Fm*(cross(eU, (angularVelocity / w)));

        // Calculate gravitational force.
        glm::vec3 gravitationForce = glm::vec3(0.f, mass * -9.82f, 0.f);

        glm::vec3 acceleration = (driveForce + magnusForce + gravitationForce) / mass;
        velocity += acceleration * static_cast<float>(time);
    }
}

void GolfBall::Render(Camera* camera, const glm::vec2& screenSize) const{
	modelObject->Render(camera, screenSize);
}

void GolfBall::Strike() {
    active = true;

    /// @todo Calculate velocity based on club mass, loft and velocity.

    velocity = glm::vec3(20.f, 5.f, 0.f);
	angularVelocity = glm::vec3(0.f,0.f,-80.f);
}

void GolfBall::SetRadius(float radius) {
    this->radius = radius;
    SetScale(2.f * glm::vec3(radius, radius, radius));
    area = glm::pi<float>() * radius * radius;
}
<commit_msg>Work on angular velocity.<commit_after>#include "GolfBall.hpp"
#include "../Resources.hpp"
#include "Default3D.vert.hpp"
#include "Default3D.geom.hpp"
#include "Default3D.frag.hpp"
#include "glm\gtc\constants.hpp"

GolfBall::GolfBall(BallType ballType) : Object() {
    active = false;

	modelGeometry = new Geometry::Model("Resources/Models/rock/Rock.bin");
	std::string diffusePath = "Resources/Models/rock/diffuse.tga";
	std::string normalPath = "Resources/Models/rock/normal.tga";
	std::string specularPath = "Resources/Models/rock/specular.tga";
	modelObject = new ModelObject(modelGeometry, diffusePath, normalPath, specularPath);
	modelObject->SetPosition(2.f, 0.f, 0.f);
	modelObject->SetScale(glm::vec3(0.01f, 0.01f, 0.01f));

    /// @todo Mass based on explosive material.
    mass = 0.0459f;
    this->ballType = ballType;

    SetRadius(0.0214f);
}

GolfBall::~GolfBall() {
	delete modelObject;
	delete modelGeometry;
}

void GolfBall::Update(double time, const glm::vec3& wind) {
    if (active) {
		modelObject->Move(static_cast<float>(time)* velocity);
		float horizontal = static_cast<float>(time)*angularVelocity.x;
		float vertical = static_cast<float>(time)*angularVelocity.y;
		float tilt = -static_cast<float>(time)*angularVelocity.z;

		modelObject->Rotate(horizontal, vertical, tilt);

        float v = velocity.length();
		float w = angularVelocity.length();
        float u = (velocity - wind).length();
		float Cm = (sqrt(1.f + 0.31f*(v/w))-1.f)/20.f;
		float Fm = 0.5f*Cm*1.23*area*u*u;

        glm::vec3 eU = (velocity - wind) / u;

        /// Calculate drive force.
        float cD;
        if (ballType == TWOPIECE) {
            cD = v < 65.f ? -0.0051f * v + 0.53f : 0.21f;
        } else {
            cD = v < 60.f ? -0.0084f * v + 0.73f : 0.22f;
        }
        glm::vec3 driveForce = -0.5f * 1.23f * area * cD * u * u * eU;

		glm::vec3 magnusForce = Fm*(cross(eU, (angularVelocity / w)));

        // Calculate gravitational force.
        glm::vec3 gravitationForce = glm::vec3(0.f, mass * -9.82f, 0.f);

        glm::vec3 acceleration = (driveForce + magnusForce + gravitationForce) / mass;
        velocity += acceleration * static_cast<float>(time);
    }
}

void GolfBall::Render(Camera* camera, const glm::vec2& screenSize) const{
	modelObject->Render(camera, screenSize);
}

void GolfBall::Strike() {
    active = true;

    /// @todo Calculate velocity based on club mass, loft and velocity.

    velocity = glm::vec3(20.f, 5.f, 0.f);
	angularVelocity = glm::vec3(0.f,0.f,-800.f);
}

void GolfBall::SetRadius(float radius) {
    this->radius = radius;
    SetScale(2.f * glm::vec3(radius, radius, radius));
    area = glm::pi<float>() * radius * radius;
}
<|endoftext|>


<commit_before>#ifdef _WIN32
#define WIN32_LEAN_AND_MEAN
#include <Windows.h>
#include <direct.h>
#else
#include <dirent.h>
#include <unistd.h>
#include <errno.h>
#endif
#include <cstring>
#include <string>
#include <set>
#include <algorithm>
#include <stdio.h>
#include <sys/stat.h>
#include <ctype.h>

#include "base/logging.h"
#include "base/basictypes.h"
#include "file/file_util.h"

#if defined(__FreeBSD__) || defined(__APPLE__) || defined(__SYMBIAN32__)
#define stat64 stat
#endif

// Hack
#ifdef __SYMBIAN32__
static inline int readdir_r(DIR *dirp, struct dirent *entry, struct dirent **result) {
    struct dirent *readdir_entry;

    readdir_entry = readdir(dirp);
    if (readdir_entry == NULL) {
        *result = NULL;
        return errno;
    }

    *entry = *readdir_entry;
    *result = entry;
    return 0;
}
#endif

bool writeStringToFile(bool text_file, const std::string &str, const char *filename)
{
	FILE *f = fopen(filename, text_file ? "w" : "wb");
	if (!f)
		return false;
	size_t len = str.size();
	if (len != fwrite(str.data(), 1, str.size(), f))
	{
		fclose(f);
		return false;
	}
	fclose(f);
	return true;
}

bool writeDataToFile(bool text_file, const void* data, const unsigned int size, const char *filename)
{
	FILE *f = fopen(filename, text_file ? "w" : "wb");
	if (!f)
		return false;
	size_t len = size;
	if (len != fwrite(data, 1, len, f))
	{
		fclose(f);
		return false;
	}
	fclose(f);
	return true;
}

uint64_t GetSize(FILE *f)
{
	// can't use off_t here because it can be 32-bit
	uint64_t pos = ftell(f);
	if (fseek(f, 0, SEEK_END) != 0) {
		return 0;
	}
	uint64_t size = ftell(f);
	// Reset the seek position to where it was when we started.
	if ((size != pos) && (fseek(f, pos, SEEK_SET) != 0)) {
		// Should error here
		return 0;
	}
	return size;
}

bool ReadFileToString(bool text_file, const char *filename, std::string &str)
{
	FILE *f = fopen(filename, text_file ? "r" : "rb");
	if (!f)
		return false;
	size_t len = (size_t)GetSize(f);
	char *buf = new char[len + 1];
	buf[fread(buf, 1, len, f)] = 0;
	str = std::string(buf, len);
	fclose(f);
	delete [] buf;
	return true;
}

bool readDataFromFile(bool text_file, unsigned char* &data, const unsigned int size, const char *filename)
{
	FILE *f = fopen(filename, text_file ? "r" : "rb");
	if (!f)
		return false;
	size_t len = (size_t)GetSize(f);
	if(len < size)
	{
		fclose(f);
		return false;
	}
	data[fread(data, 1, size, f)] = 0;
	fclose(f);
	return true;
}

#define DIR_SEP "/"
#define DIR_SEP_CHR '\\'

#ifndef METRO

// Remove any ending forward slashes from directory paths
// Modifies argument.
static void stripTailDirSlashes(std::string &fname)
{
	if (fname.length() > 1)
	{
		size_t i = fname.length() - 1;
		while (fname[i] == DIR_SEP_CHR)
			fname[i--] = '\0';
	}
	return;
}

// Returns true if file filename exists
bool exists(const std::string &filename)
{
#ifdef _WIN32
	return GetFileAttributes(filename.c_str()) != 0xFFFFFFFF;
#else
	struct stat64 file_info;

	std::string copy(filename);
	stripTailDirSlashes(copy);

	int result = stat64(copy.c_str(), &file_info);

	return (result == 0);
#endif
}

// Returns true if filename is a directory
bool isDirectory(const std::string &filename)
{
	FileInfo info;
	getFileInfo(filename.c_str(), &info);
	return info.isDirectory;
}

bool getFileInfo(const char *path, FileInfo *fileInfo)
{
	// TODO: Expand relative paths?
	fileInfo->fullName = path;

#ifdef _WIN32
	fileInfo->size = 0;
	WIN32_FILE_ATTRIBUTE_DATA attrs;
	if (GetFileAttributesExA(path, GetFileExInfoStandard, &attrs)) {
		fileInfo->size = (uint64_t)attrs.nFileSizeLow | ((uint64_t)attrs.nFileSizeHigh << 32);
	}
	fileInfo->isDirectory = (attrs.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) != 0;
	fileInfo->isWritable = (attrs.dwFileAttributes & FILE_ATTRIBUTE_READONLY) == 0;
#else
	struct stat64 file_info;

	std::string copy(path);
	stripTailDirSlashes(copy);

	int result = stat64(copy.c_str(), &file_info);

	if (result < 0) {
		WLOG("IsDirectory: stat failed on %s", path);
		return false;
	}

	fileInfo->isDirectory = S_ISDIR(file_info.st_mode);
	fileInfo->isWritable = false;
	fileInfo->size = file_info.st_size;
	// HACK: approximation
	if (file_info.st_mode & 0200)
		fileInfo->isWritable = true;
#endif
	return true;
}

std::string getFileExtension(const std::string &fn) {
	int pos = fn.rfind(".");
	if (pos < 0) return "";
	std::string ext = fn.substr(pos+1);
	for (size_t i = 0; i < ext.size(); i++) {
		ext[i] = tolower(ext[i]);
	}
	return ext;
}

size_t getFilesInDir(const char *directory, std::vector<FileInfo> *files, const char *filter) {
	size_t foundEntries = 0;
	std::set<std::string> filters;
	std::string tmp;
	if (filter) {
		while (*filter) {
			if (*filter == ':') {
				filters.insert(tmp);
				tmp = "";
			} else {
				tmp.push_back(*filter);
			}
			filter++;
		}
	}
	if (tmp.size())
		filters.insert(tmp);
#ifdef _WIN32
	// Find the first file in the directory.
	WIN32_FIND_DATA ffd;
#ifdef UNICODE
	HANDLE hFind = FindFirstFile((std::wstring(directory) + "\\*").c_str(), &ffd);
#else
	HANDLE hFind = FindFirstFile((std::string(directory) + "\\*").c_str(), &ffd);
#endif
	if (hFind == INVALID_HANDLE_VALUE) {
		FindClose(hFind);
		return 0;
	}
	// windows loop
	do
	{
		const std::string virtualName(ffd.cFileName);
#else
	struct dirent_large { struct dirent entry; char padding[FILENAME_MAX+1]; };
	struct dirent_large diren;
	struct dirent *result = NULL;

	DIR *dirp = opendir(directory);
	if (!dirp)
		return 0;
	// non windows loop
	while (!readdir_r(dirp, (dirent*) &diren, &result) && result)
	{
		const std::string virtualName(result->d_name);
#endif
		// check for "." and ".."
		if (((virtualName[0] == '.') && (virtualName[1] == '\0')) ||
			((virtualName[0] == '.') && (virtualName[1] == '.') &&
			(virtualName[2] == '\0')))
			continue;

		// Remove dotfiles (should be made optional?)
		if (virtualName[0] == '.')
			continue;

		FileInfo info;
		info.name = virtualName;
		info.fullName = std::string(directory) + "/" + virtualName;
		info.isDirectory = isDirectory(info.fullName);
		info.exists = true;
		if (!info.isDirectory) {
			std::string ext = getFileExtension(info.fullName);
			if (filter) {
				if (filters.find(ext) == filters.end())
					continue;
			}
		}

		files->push_back(info);
#ifdef _WIN32
	} while (FindNextFile(hFind, &ffd) != 0);
	FindClose(hFind);
#else
	}
	closedir(dirp);
#endif
	std::sort(files->begin(), files->end());
	return foundEntries;
}

void deleteFile(const char *file)
{
#ifdef _WIN32
	if (!DeleteFile(file)) {
		ELOG("Error deleting %s: %i", file, GetLastError());
	}
#else
	int err = unlink(file);
	if (err) {
		ELOG("Error unlinking %s: %i", file, err);
	}
#endif
}
#endif

std::string getDir(const std::string &path)
{
	if (path == "/")
		return path;
	int n = path.size() - 1;
	while (n >= 0 && path[n] != '\\' && path[n] != '/')
		n--;
	std::string cutpath = n > 0 ? path.substr(0, n) : "";
	for (size_t i = 0; i < cutpath.size(); i++)
	{
		if (cutpath[i] == '\\') cutpath[i] = '/';
	}
#ifndef _WIN32
	if (!cutpath.size()) {
		return "/";
	}
#endif
	return cutpath;
}

void mkDir(const std::string &path)
{
#ifdef _WIN32
	mkdir(path.c_str());
#else
	mkdir(path.c_str(), 0777);
#endif
}
<commit_msg>Win32: Make getFileInfo() fail and label the path non-directory when GetFileAttributesExA fails<commit_after>#ifdef _WIN32
#define WIN32_LEAN_AND_MEAN
#include <Windows.h>
#include <direct.h>
#else
#include <dirent.h>
#include <unistd.h>
#include <errno.h>
#endif
#include <cstring>
#include <string>
#include <set>
#include <algorithm>
#include <stdio.h>
#include <sys/stat.h>
#include <ctype.h>

#include "base/logging.h"
#include "base/basictypes.h"
#include "file/file_util.h"

#if defined(__FreeBSD__) || defined(__APPLE__) || defined(__SYMBIAN32__)
#define stat64 stat
#endif

// Hack
#ifdef __SYMBIAN32__
static inline int readdir_r(DIR *dirp, struct dirent *entry, struct dirent **result) {
    struct dirent *readdir_entry;

    readdir_entry = readdir(dirp);
    if (readdir_entry == NULL) {
        *result = NULL;
        return errno;
    }

    *entry = *readdir_entry;
    *result = entry;
    return 0;
}
#endif

bool writeStringToFile(bool text_file, const std::string &str, const char *filename)
{
	FILE *f = fopen(filename, text_file ? "w" : "wb");
	if (!f)
		return false;
	size_t len = str.size();
	if (len != fwrite(str.data(), 1, str.size(), f))
	{
		fclose(f);
		return false;
	}
	fclose(f);
	return true;
}

bool writeDataToFile(bool text_file, const void* data, const unsigned int size, const char *filename)
{
	FILE *f = fopen(filename, text_file ? "w" : "wb");
	if (!f)
		return false;
	size_t len = size;
	if (len != fwrite(data, 1, len, f))
	{
		fclose(f);
		return false;
	}
	fclose(f);
	return true;
}

uint64_t GetSize(FILE *f)
{
	// can't use off_t here because it can be 32-bit
	uint64_t pos = ftell(f);
	if (fseek(f, 0, SEEK_END) != 0) {
		return 0;
	}
	uint64_t size = ftell(f);
	// Reset the seek position to where it was when we started.
	if ((size != pos) && (fseek(f, pos, SEEK_SET) != 0)) {
		// Should error here
		return 0;
	}
	return size;
}

bool ReadFileToString(bool text_file, const char *filename, std::string &str)
{
	FILE *f = fopen(filename, text_file ? "r" : "rb");
	if (!f)
		return false;
	size_t len = (size_t)GetSize(f);
	char *buf = new char[len + 1];
	buf[fread(buf, 1, len, f)] = 0;
	str = std::string(buf, len);
	fclose(f);
	delete [] buf;
	return true;
}

bool readDataFromFile(bool text_file, unsigned char* &data, const unsigned int size, const char *filename)
{
	FILE *f = fopen(filename, text_file ? "r" : "rb");
	if (!f)
		return false;
	size_t len = (size_t)GetSize(f);
	if(len < size)
	{
		fclose(f);
		return false;
	}
	data[fread(data, 1, size, f)] = 0;
	fclose(f);
	return true;
}

#define DIR_SEP "/"
#define DIR_SEP_CHR '\\'

#ifndef METRO

// Remove any ending forward slashes from directory paths
// Modifies argument.
static void stripTailDirSlashes(std::string &fname)
{
	if (fname.length() > 1)
	{
		size_t i = fname.length() - 1;
		while (fname[i] == DIR_SEP_CHR)
			fname[i--] = '\0';
	}
	return;
}

// Returns true if file filename exists
bool exists(const std::string &filename)
{
#ifdef _WIN32
	return GetFileAttributes(filename.c_str()) != 0xFFFFFFFF;
#else
	struct stat64 file_info;

	std::string copy(filename);
	stripTailDirSlashes(copy);

	int result = stat64(copy.c_str(), &file_info);

	return (result == 0);
#endif
}

// Returns true if filename is a directory
bool isDirectory(const std::string &filename)
{
	FileInfo info;
	getFileInfo(filename.c_str(), &info);
	return info.isDirectory;
}

bool getFileInfo(const char *path, FileInfo *fileInfo)
{
	// TODO: Expand relative paths?
	fileInfo->fullName = path;

#ifdef _WIN32
	WIN32_FILE_ATTRIBUTE_DATA attrs;
	if (!GetFileAttributesExA(path, GetFileExInfoStandard, &attrs)) {
		fileInfo->size = 0;
		fileInfo->isDirectory = false;
		return false;
	}
	fileInfo->size = (uint64_t)attrs.nFileSizeLow | ((uint64_t)attrs.nFileSizeHigh << 32);
	fileInfo->isDirectory = (attrs.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) != 0;
	fileInfo->isWritable = (attrs.dwFileAttributes & FILE_ATTRIBUTE_READONLY) == 0;
#else
	struct stat64 file_info;

	std::string copy(path);
	stripTailDirSlashes(copy);

	int result = stat64(copy.c_str(), &file_info);

	if (result < 0) {
		WLOG("IsDirectory: stat failed on %s", path);
		return false;
	}

	fileInfo->isDirectory = S_ISDIR(file_info.st_mode);
	fileInfo->isWritable = false;
	fileInfo->size = file_info.st_size;
	// HACK: approximation
	if (file_info.st_mode & 0200)
		fileInfo->isWritable = true;
#endif
	return true;
}

std::string getFileExtension(const std::string &fn) {
	int pos = fn.rfind(".");
	if (pos < 0) return "";
	std::string ext = fn.substr(pos+1);
	for (size_t i = 0; i < ext.size(); i++) {
		ext[i] = tolower(ext[i]);
	}
	return ext;
}

size_t getFilesInDir(const char *directory, std::vector<FileInfo> *files, const char *filter) {
	size_t foundEntries = 0;
	std::set<std::string> filters;
	std::string tmp;
	if (filter) {
		while (*filter) {
			if (*filter == ':') {
				filters.insert(tmp);
				tmp = "";
			} else {
				tmp.push_back(*filter);
			}
			filter++;
		}
	}
	if (tmp.size())
		filters.insert(tmp);
#ifdef _WIN32
	// Find the first file in the directory.
	WIN32_FIND_DATA ffd;
#ifdef UNICODE
	HANDLE hFind = FindFirstFile((std::wstring(directory) + "\\*").c_str(), &ffd);
#else
	HANDLE hFind = FindFirstFile((std::string(directory) + "\\*").c_str(), &ffd);
#endif
	if (hFind == INVALID_HANDLE_VALUE) {
		FindClose(hFind);
		return 0;
	}
	// windows loop
	do
	{
		const std::string virtualName(ffd.cFileName);
#else
	struct dirent_large { struct dirent entry; char padding[FILENAME_MAX+1]; };
	struct dirent_large diren;
	struct dirent *result = NULL;

	DIR *dirp = opendir(directory);
	if (!dirp)
		return 0;
	// non windows loop
	while (!readdir_r(dirp, (dirent*) &diren, &result) && result)
	{
		const std::string virtualName(result->d_name);
#endif
		// check for "." and ".."
		if (((virtualName[0] == '.') && (virtualName[1] == '\0')) ||
			((virtualName[0] == '.') && (virtualName[1] == '.') &&
			(virtualName[2] == '\0')))
			continue;

		// Remove dotfiles (should be made optional?)
		if (virtualName[0] == '.')
			continue;

		FileInfo info;
		info.name = virtualName;
		info.fullName = std::string(directory) + "/" + virtualName;
		info.isDirectory = isDirectory(info.fullName);
		info.exists = true;
		if (!info.isDirectory) {
			std::string ext = getFileExtension(info.fullName);
			if (filter) {
				if (filters.find(ext) == filters.end())
					continue;
			}
		}

		files->push_back(info);
#ifdef _WIN32
	} while (FindNextFile(hFind, &ffd) != 0);
	FindClose(hFind);
#else
	}
	closedir(dirp);
#endif
	std::sort(files->begin(), files->end());
	return foundEntries;
}

void deleteFile(const char *file)
{
#ifdef _WIN32
	if (!DeleteFile(file)) {
		ELOG("Error deleting %s: %i", file, GetLastError());
	}
#else
	int err = unlink(file);
	if (err) {
		ELOG("Error unlinking %s: %i", file, err);
	}
#endif
}
#endif

std::string getDir(const std::string &path)
{
	if (path == "/")
		return path;
	int n = path.size() - 1;
	while (n >= 0 && path[n] != '\\' && path[n] != '/')
		n--;
	std::string cutpath = n > 0 ? path.substr(0, n) : "";
	for (size_t i = 0; i < cutpath.size(); i++)
	{
		if (cutpath[i] == '\\') cutpath[i] = '/';
	}
#ifndef _WIN32
	if (!cutpath.size()) {
		return "/";
	}
#endif
	return cutpath;
}

void mkDir(const std::string &path)
{
#ifdef _WIN32
	mkdir(path.c_str());
#else
	mkdir(path.c_str(), 0777);
#endif
}
<|endoftext|>


<commit_before>#include <iostream>

#include <stdexcept>

#include <QClipboard>
#include <QMessageBox>
#include <QSettings>
#include <QSharedPointer>
#include <QWidget>
#include <QFile>

#include <CorpusWidget.hh>
#include <DactMacrosModel.hh>
#include <DactToolsMenu.hh>
#include <DactToolsModel.hh>
#include <DactTreeScene.hh>
#include <DactTreeView.hh>
#include <DependencyTreeWidget.hh>
#include <FilterModel.hh>
#include <ValidityColor.hh>
#include <XPathValidator.hh>

#include "ui_DependencyTreeWidget.h"

DependencyTreeWidget::DependencyTreeWidget(QWidget *parent) :
    CorpusWidget(parent),
    d_ui(QSharedPointer<Ui::DependencyTreeWidget>(new Ui::DependencyTreeWidget)),
    d_macrosModel(QSharedPointer<DactMacrosModel>(new DactMacrosModel()))
{
    d_ui->setupUi(this);

    addConnections();

    // Statistics are only shown after we have all entries, or when a
    // query is executed...
    d_ui->statisticsGroupBox->hide();

    d_ui->hitsDescLabel->hide();
    d_ui->hitsLabel->hide();
    d_ui->statisticsLayout->setVerticalSpacing(0);
}

DependencyTreeWidget::~DependencyTreeWidget()
{
    // Define a destructor here to make sure the qsharedpointers are implemented where all
    // the proper header files are available (not just forward declarations)
}

void DependencyTreeWidget::addConnections()
{
    connect(d_ui->highlightLineEdit, SIGNAL(textChanged(QString const &)),
            SLOT(applyValidityColor(QString const &)));
    connect(d_ui->highlightLineEdit, SIGNAL(returnPressed()),
            SLOT(highlightChanged()));
    connect(d_ui->treeGraphicsView, SIGNAL(sceneChanged(DactTreeScene*)),
            SIGNAL(sceneChanged(DactTreeScene*)));
}

void DependencyTreeWidget::applyValidityColor(QString const &)
{
    ::applyValidityColor(sender());
}

BracketedSentenceWidget *DependencyTreeWidget::sentenceWidget()
{
    return d_ui->sentenceWidget;
}

void DependencyTreeWidget::cancelQuery()
{
    if (d_model)
        d_model->cancelQuery();
}

void DependencyTreeWidget::saveAs()
{
    std::cerr << "Dependency Tree Widget Save As" << std::endl;
}

bool DependencyTreeWidget::saveEnabled() const
{
    return false;
}

void DependencyTreeWidget::copy()
{
    if (!d_model)
        return;

    QStringList filenames;

    QModelIndexList indices = d_ui->fileListWidget->selectionModel()->selectedIndexes();

    for (QModelIndexList::const_iterator iter = indices.begin();
        iter != indices.end(); ++iter)
    {
        QVariant v = d_model->data(*iter, Qt::DisplayRole);
        if (v.type() == QVariant::String)
            filenames.push_back(v.toString());
    }

    QApplication::clipboard()->setText(filenames.join("\n")); // XXX - Good enough for Windows?
}

void DependencyTreeWidget::nEntriesFound(int entries, int hits) {
    d_ui->entriesLabel->setText(QString("%L1").arg(entries));
    d_ui->hitsLabel->setText(QString("%L1").arg(hits));

    if (!d_treeShown) {
        d_ui->fileListWidget->selectionModel()->clear();
        QModelIndex idx(d_model->index(0, 0));
        d_ui->fileListWidget->selectionModel()->setCurrentIndex(idx,
                                                                QItemSelectionModel::ClearAndSelect);
        d_treeShown = true;
    }
}

void DependencyTreeWidget::entrySelected(QModelIndex const &current, QModelIndex const &prev)
{
    Q_UNUSED(prev);

    if (!current.isValid()) {
        d_ui->treeGraphicsView->setScene(0);
        d_ui->sentenceWidget->clear();
        return;
    }

    showFile(current.data(Qt::UserRole).toString());

    //focusFitTree();
    focusFirstMatch();
}

void DependencyTreeWidget::fitTree()
{
    d_ui->treeGraphicsView->fitTree();
}

void DependencyTreeWidget::focusFirstMatch()
{
    if (d_ui->treeGraphicsView->scene() &&
        d_ui->treeGraphicsView->scene()->activeNodes().length() > 0)
      d_ui->treeGraphicsView->focusTreeNode(1);
}

void DependencyTreeWidget::focusFitTree()
{
    if (d_ui->treeGraphicsView->scene()
        && d_ui->treeGraphicsView->scene()->activeNodes().length())
    {
        d_ui->treeGraphicsView->resetZoom();
        d_ui->treeGraphicsView->focusTreeNode(1);
    }
    else
        d_ui->treeGraphicsView->fitTree();
}

void DependencyTreeWidget::focusHighlight()
{
    d_ui->highlightLineEdit->setFocus();
}

void DependencyTreeWidget::focusNextTreeNode()
{
    d_ui->treeGraphicsView->focusNextTreeNode();
}

void DependencyTreeWidget::focusPreviousTreeNode()
{
    d_ui->treeGraphicsView->focusPreviousTreeNode();
}

void DependencyTreeWidget::highlightChanged()
{
    setHighlight(d_ui->highlightLineEdit->text().trimmed());
}

void DependencyTreeWidget::mapperStarted(int totalEntries)
{
    d_ui->entriesLabel->setText(QString::number(0));
    d_ui->hitsLabel->setText(QString::number(0));

    if (!d_filter.isEmpty()) {
        d_ui->filterProgressBar->setMinimum(0);
        d_ui->filterProgressBar->setMaximum(totalEntries);
        d_ui->filterProgressBar->setValue(0);
        d_ui->filterProgressBar->setVisible(true);
    }
}

void DependencyTreeWidget::mapperFailed(QString error)
{
    d_ui->filterProgressBar->setVisible(false);
    QMessageBox::critical(this, tr("Error processing query"),
                          tr("Could not process query: ") + error,
                          QMessageBox::Ok);
}

void DependencyTreeWidget::mapperFinished(int processedEntries, int totalEntries, bool cached)
{
    if (cached) {
        d_ui->fileListWidget->selectionModel()->clear();
        QModelIndex idx(d_model->index(0, 0));
        d_ui->fileListWidget->selectionModel()->setCurrentIndex(idx,
            QItemSelectionModel::ClearAndSelect);
    }

    mapperStopped(processedEntries, totalEntries);
}

void DependencyTreeWidget::mapperStopped(int processedEntries, int totalEntries)
{
    if (!d_filter.isEmpty())
        d_ui->filterProgressBar->setVisible(false);

    // Final counts. Doing this again is necessary, because the query may
    // have been cached. If so, it doesn't emit a signal for every entry.
    int entries = d_model->rowCount(QModelIndex());
    int hits = d_model->hits();
    d_ui->entriesLabel->setText(QString("%L1").arg(entries));
    d_ui->hitsLabel->setText(QString("%L1").arg(hits));

    if (!d_file.isNull())
    {
        QModelIndex current = d_model->indexOfFile(d_file);
        d_ui->fileListWidget->setCurrentIndex(current);
    }
}

/* Next- and prev entry buttons */

void DependencyTreeWidget::nextEntry(bool)
{
    QModelIndex current(d_ui->fileListWidget->currentIndex());
    QModelIndex next = current.sibling(current.row() + 1, current.column());
    if (next.isValid())
        d_ui->fileListWidget->setCurrentIndex(next);
}

void DependencyTreeWidget::previousEntry(bool)
{
    QModelIndex current(d_ui->fileListWidget->currentIndex());
    QModelIndex previous = current.sibling(current.row() - 1, current.column());
    if (previous.isValid())
        d_ui->fileListWidget->setCurrentIndex(previous);
}

void DependencyTreeWidget::progressChanged(int progress)
{
    d_ui->filterProgressBar->setValue(progress);
}

void DependencyTreeWidget::readSettings()
{
    QSettings settings;

    // Splitter.
    d_ui->splitter->restoreState(
        settings.value("splitterSizes").toByteArray());
}

void DependencyTreeWidget::renderTree(QPainter *painter)
{
    if (d_ui->treeGraphicsView->scene())
        d_ui->treeGraphicsView->scene()->render(painter);
}

DactTreeScene *DependencyTreeWidget::scene()
{
    return d_ui->treeGraphicsView->scene();
}

QItemSelectionModel *DependencyTreeWidget::selectionModel()
{
    return d_ui->fileListWidget->selectionModel();
}

void DependencyTreeWidget::setFilter(QString const &filter, QString const &raw_filter)
{
    d_filter = filter;
    d_treeShown = false;
    d_file = QString();

    if (d_filter.isEmpty()) {
        d_ui->statisticsGroupBox->hide();
        d_ui->hitsDescLabel->hide();
        d_ui->hitsLabel->hide();
        d_ui->statisticsLayout->setVerticalSpacing(0);
    } else {
        d_ui->statisticsGroupBox->show();
        d_ui->statisticsLayout->setVerticalSpacing(-1);
        d_ui->hitsDescLabel->show();
        d_ui->hitsLabel->show();
    }

    setHighlight(raw_filter);

    if (d_model)
        d_model->runQuery(d_filter);
}

void DependencyTreeWidget::setModel(FilterModel *model)
{
    d_model = QSharedPointer<FilterModel>(model);
    d_ui->fileListWidget->setModel(d_model.data());

    connect(model, SIGNAL(queryFailed(QString)),
            SLOT(mapperFailed(QString)));
    connect(model, SIGNAL(queryStarted(int)),
            SLOT(mapperStarted(int)));
    connect(model, SIGNAL(queryStopped(int, int)),
            SLOT(mapperStopped(int, int)));
    connect(model, SIGNAL(queryFinished(int, int, bool)),
            SLOT(mapperFinished(int, int, bool)));
    connect(model, SIGNAL(nEntriesFound(int, int)),
            SLOT(nEntriesFound(int, int)));
    connect(model, SIGNAL(progressChanged(int)),
            SLOT(progressChanged(int)));

    connect(d_ui->fileListWidget->selectionModel(),
            SIGNAL(currentChanged(QModelIndex,QModelIndex)),
            SLOT(entrySelected(QModelIndex,QModelIndex)));
}

void DependencyTreeWidget::setMacrosModel(QSharedPointer<DactMacrosModel> macrosModel)
{
    d_macrosModel = macrosModel;
    d_xpathValidator = QSharedPointer<XPathValidator>(new XPathValidator(d_macrosModel));
    d_ui->highlightLineEdit->setValidator(d_xpathValidator.data());
}

void DependencyTreeWidget::setHighlight(QString const &query)
{
    d_highlight = query;
    d_ui->highlightLineEdit->setText(query);
    showFile(); // to force-reload the tree and bracketed sentence
}

void DependencyTreeWidget::showFile()
{
    if (!d_file.isNull())
        showFile(d_file);
}

void DependencyTreeWidget::showFile(QString const &entry)
{
    // Read XML data.
    if (d_corpusReader.isNull())
        return;

    try {
        QString xml;
        if (d_highlight.trimmed().isEmpty())
            xml = QString::fromUtf8(d_corpusReader->read(entry.toUtf8().constData()).c_str());
        else {
            ac::CorpusReader::MarkerQuery query(d_macrosModel->expand(d_highlight).toUtf8().constData(),
                                                "active", "1");
            std::list<ac::CorpusReader::MarkerQuery> queries;
            queries.push_back(query);
            xml = QString::fromUtf8(d_corpusReader->read(entry.toUtf8().constData(), queries).c_str());
        }

        if (xml.size() == 0) {
            qWarning() << "MainWindow::writeSettings: empty XML data!";
            d_ui->treeGraphicsView->setScene(0);
            return;
        }

        // Remember file for when we need to redraw the tree
        d_file = entry;

        // Parameters
        QString valStr = d_highlight.trimmed().isEmpty() ? "'/..'" :
        QString("'") + d_macrosModel->expand(d_highlight) + QString("'");
        QHash<QString, QString> params;
        params["expr"] = valStr;

        try {
            showTree(xml);
            showSentence(entry, d_highlight);

            // I try to find my file back in the file list to keep the list
            // in sync with the treegraph since showFile can be called from
            // the child dialogs.

            QModelIndexList matches =
              d_ui->fileListWidget->model()->match(
                  d_ui->fileListWidget->model()->index(0, 0),
                  Qt::DisplayRole, entry, 1,
                  Qt::MatchFixedString | Qt::MatchCaseSensitive);
            if (matches.size() > 0) {
              d_ui->fileListWidget->selectionModel()->select(matches.at(0),
                  QItemSelectionModel::ClearAndSelect);
              d_ui->fileListWidget->scrollTo(matches.at(0));
            }
        } catch (std::runtime_error const &e) {
            QMessageBox::critical(this, QString("Tranformation error"),
                                  QString("A transformation error occured: %1\n\nCorpus data is probably corrupt.").arg(e.what()));
        }
    }
    catch(std::runtime_error const &e)
    {
        QMessageBox::critical(this, QString("Read error"),
                              QString("An error occured while trying to read a corpus file: %1").arg(e.what()));
    }
}

void DependencyTreeWidget::showSentence(QString const &entry, QString const &query)
{
    d_ui->sentenceWidget->setEntry(entry, d_macrosModel->expand(query));
}

void DependencyTreeWidget::showTree(QString const &xml)
{
    d_ui->treeGraphicsView->showTree(xml);
}

void DependencyTreeWidget::switchCorpus(QSharedPointer<alpinocorpus::CorpusReader> corpusReader)
{
    d_corpusReader = corpusReader;

    d_xpathValidator->setCorpusReader(d_corpusReader);

    setModel(new FilterModel(d_corpusReader));

    QString query = d_ui->highlightLineEdit->text();
    d_ui->highlightLineEdit->clear();
    d_ui->highlightLineEdit->insert(query);

    d_model->runQuery(d_macrosModel->expand(d_filter));

    d_ui->sentenceWidget->setCorpusReader(d_corpusReader);
}

void DependencyTreeWidget::writeSettings()
{
    QSettings settings;

    // Splitter
    settings.setValue("splitterSizes", d_ui->splitter->saveState());
}

void DependencyTreeWidget::zoomIn()
{
    d_ui->treeGraphicsView->zoomIn();
}

void DependencyTreeWidget::zoomOut()
{
    d_ui->treeGraphicsView->zoomOut();
}

void DependencyTreeWidget::showToolMenu(QPoint const &position)
{
    if (!d_ui->fileListWidget->model())
        return;

    QModelIndexList rows = d_ui->fileListWidget->selectionModel()->selectedRows();
    QList<QString> selectedFiles;

    if (rows.isEmpty())
        return;

    foreach (QModelIndex const &row, rows)
        selectedFiles << row.data().toString();

    DactToolsMenu::exec(
        DactToolsModel::sharedInstance()->tools(QString::fromStdString(d_corpusReader->name())),
        selectedFiles,
        mapToGlobal(position),
        d_ui->fileListWidget->actions());
}
<commit_msg>Remove a race condition.<commit_after>#include <iostream>

#include <stdexcept>

#include <QClipboard>
#include <QMessageBox>
#include <QSettings>
#include <QSharedPointer>
#include <QWidget>
#include <QFile>

#include <CorpusWidget.hh>
#include <DactMacrosModel.hh>
#include <DactToolsMenu.hh>
#include <DactToolsModel.hh>
#include <DactTreeScene.hh>
#include <DactTreeView.hh>
#include <DependencyTreeWidget.hh>
#include <FilterModel.hh>
#include <ValidityColor.hh>
#include <XPathValidator.hh>

#include "ui_DependencyTreeWidget.h"

// Note that there is a race in this class, when a new filter is set.
// d_model->runQuery may cancel an existing query, delivering a queryStopped()
// signal. However, at that point d_filter is already reset. Since queries
// run in a separate thread, we cannot connect signals directly.
//
// Consequence: don't rely on d_filter if the code path is treating stopping
// of an older query.

DependencyTreeWidget::DependencyTreeWidget(QWidget *parent) :
    CorpusWidget(parent),
    d_ui(QSharedPointer<Ui::DependencyTreeWidget>(new Ui::DependencyTreeWidget)),
    d_macrosModel(QSharedPointer<DactMacrosModel>(new DactMacrosModel()))
{
    d_ui->setupUi(this);

    addConnections();

    // Statistics are only shown after we have all entries, or when a
    // query is executed...
    d_ui->statisticsGroupBox->hide();

    d_ui->hitsDescLabel->hide();
    d_ui->hitsLabel->hide();
    d_ui->statisticsLayout->setVerticalSpacing(0);
}

DependencyTreeWidget::~DependencyTreeWidget()
{
    // Define a destructor here to make sure the qsharedpointers are implemented where all
    // the proper header files are available (not just forward declarations)
}

void DependencyTreeWidget::addConnections()
{
    connect(d_ui->highlightLineEdit, SIGNAL(textChanged(QString const &)),
            SLOT(applyValidityColor(QString const &)));
    connect(d_ui->highlightLineEdit, SIGNAL(returnPressed()),
            SLOT(highlightChanged()));
    connect(d_ui->treeGraphicsView, SIGNAL(sceneChanged(DactTreeScene*)),
            SIGNAL(sceneChanged(DactTreeScene*)));
}

void DependencyTreeWidget::applyValidityColor(QString const &)
{
    ::applyValidityColor(sender());
}

BracketedSentenceWidget *DependencyTreeWidget::sentenceWidget()
{
    return d_ui->sentenceWidget;
}

void DependencyTreeWidget::cancelQuery()
{
    if (d_model)
        d_model->cancelQuery();
}

void DependencyTreeWidget::saveAs()
{
    std::cerr << "Dependency Tree Widget Save As" << std::endl;
}

bool DependencyTreeWidget::saveEnabled() const
{
    return false;
}

void DependencyTreeWidget::copy()
{
    if (!d_model)
        return;

    QStringList filenames;

    QModelIndexList indices = d_ui->fileListWidget->selectionModel()->selectedIndexes();

    for (QModelIndexList::const_iterator iter = indices.begin();
        iter != indices.end(); ++iter)
    {
        QVariant v = d_model->data(*iter, Qt::DisplayRole);
        if (v.type() == QVariant::String)
            filenames.push_back(v.toString());
    }

    QApplication::clipboard()->setText(filenames.join("\n")); // XXX - Good enough for Windows?
}

void DependencyTreeWidget::nEntriesFound(int entries, int hits) {
    d_ui->entriesLabel->setText(QString("%L1").arg(entries));
    d_ui->hitsLabel->setText(QString("%L1").arg(hits));

    if (!d_treeShown) {
        d_ui->fileListWidget->selectionModel()->clear();
        QModelIndex idx(d_model->index(0, 0));
        d_ui->fileListWidget->selectionModel()->setCurrentIndex(idx,
                                                                QItemSelectionModel::ClearAndSelect);
        d_treeShown = true;
    }
}

void DependencyTreeWidget::entrySelected(QModelIndex const &current, QModelIndex const &prev)
{
    Q_UNUSED(prev);

    if (!current.isValid()) {
        d_ui->treeGraphicsView->setScene(0);
        d_ui->sentenceWidget->clear();
        return;
    }

    showFile(current.data(Qt::UserRole).toString());

    //focusFitTree();
    focusFirstMatch();
}

void DependencyTreeWidget::fitTree()
{
    d_ui->treeGraphicsView->fitTree();
}

void DependencyTreeWidget::focusFirstMatch()
{
    if (d_ui->treeGraphicsView->scene() &&
        d_ui->treeGraphicsView->scene()->activeNodes().length() > 0)
      d_ui->treeGraphicsView->focusTreeNode(1);
}

void DependencyTreeWidget::focusFitTree()
{
    if (d_ui->treeGraphicsView->scene()
        && d_ui->treeGraphicsView->scene()->activeNodes().length())
    {
        d_ui->treeGraphicsView->resetZoom();
        d_ui->treeGraphicsView->focusTreeNode(1);
    }
    else
        d_ui->treeGraphicsView->fitTree();
}

void DependencyTreeWidget::focusHighlight()
{
    d_ui->highlightLineEdit->setFocus();
}

void DependencyTreeWidget::focusNextTreeNode()
{
    d_ui->treeGraphicsView->focusNextTreeNode();
}

void DependencyTreeWidget::focusPreviousTreeNode()
{
    d_ui->treeGraphicsView->focusPreviousTreeNode();
}

void DependencyTreeWidget::highlightChanged()
{
    setHighlight(d_ui->highlightLineEdit->text().trimmed());
}

void DependencyTreeWidget::mapperStarted(int totalEntries)
{
    d_ui->entriesLabel->setText(QString::number(0));
    d_ui->hitsLabel->setText(QString::number(0));

    if (!d_filter.isEmpty()) {
        d_ui->filterProgressBar->setMinimum(0);
        d_ui->filterProgressBar->setMaximum(totalEntries);
        d_ui->filterProgressBar->setValue(0);
        d_ui->filterProgressBar->setVisible(true);
    }
}

void DependencyTreeWidget::mapperFailed(QString error)
{
    d_ui->filterProgressBar->setVisible(false);
    QMessageBox::critical(this, tr("Error processing query"),
                          tr("Could not process query: ") + error,
                          QMessageBox::Ok);
}

void DependencyTreeWidget::mapperFinished(int processedEntries, int totalEntries, bool cached)
{
    if (cached) {
        d_ui->fileListWidget->selectionModel()->clear();
        QModelIndex idx(d_model->index(0, 0));
        d_ui->fileListWidget->selectionModel()->setCurrentIndex(idx,
            QItemSelectionModel::ClearAndSelect);
    }

    mapperStopped(processedEntries, totalEntries);
}

void DependencyTreeWidget::mapperStopped(int processedEntries, int totalEntries)
{
    d_ui->filterProgressBar->setVisible(false);

    // Final counts. Doing this again is necessary, because the query may
    // have been cached. If so, it doesn't emit a signal for every entry.
    int entries = d_model->rowCount(QModelIndex());
    int hits = d_model->hits();
    d_ui->entriesLabel->setText(QString("%L1").arg(entries));
    d_ui->hitsLabel->setText(QString("%L1").arg(hits));

    if (!d_file.isNull())
    {
        QModelIndex current = d_model->indexOfFile(d_file);
        d_ui->fileListWidget->setCurrentIndex(current);
    }
}

/* Next- and prev entry buttons */

void DependencyTreeWidget::nextEntry(bool)
{
    QModelIndex current(d_ui->fileListWidget->currentIndex());
    QModelIndex next = current.sibling(current.row() + 1, current.column());
    if (next.isValid())
        d_ui->fileListWidget->setCurrentIndex(next);
}

void DependencyTreeWidget::previousEntry(bool)
{
    QModelIndex current(d_ui->fileListWidget->currentIndex());
    QModelIndex previous = current.sibling(current.row() - 1, current.column());
    if (previous.isValid())
        d_ui->fileListWidget->setCurrentIndex(previous);
}

void DependencyTreeWidget::progressChanged(int progress)
{
    d_ui->filterProgressBar->setValue(progress);
}

void DependencyTreeWidget::readSettings()
{
    QSettings settings;

    // Splitter.
    d_ui->splitter->restoreState(
        settings.value("splitterSizes").toByteArray());
}

void DependencyTreeWidget::renderTree(QPainter *painter)
{
    if (d_ui->treeGraphicsView->scene())
        d_ui->treeGraphicsView->scene()->render(painter);
}

DactTreeScene *DependencyTreeWidget::scene()
{
    return d_ui->treeGraphicsView->scene();
}

QItemSelectionModel *DependencyTreeWidget::selectionModel()
{
    return d_ui->fileListWidget->selectionModel();
}

void DependencyTreeWidget::setFilter(QString const &filter, QString const &raw_filter)
{
    d_treeShown = false;
    d_file = QString();

    if (filter.isEmpty()) {
        d_ui->statisticsGroupBox->hide();
        d_ui->hitsDescLabel->hide();
        d_ui->hitsLabel->hide();
        d_ui->statisticsLayout->setVerticalSpacing(0);
    } else {
        d_ui->statisticsGroupBox->show();
        d_ui->statisticsLayout->setVerticalSpacing(-1);
        d_ui->hitsDescLabel->show();
        d_ui->hitsLabel->show();
    }

    setHighlight(raw_filter);

    if (d_model)
        d_model->runQuery(filter);

    d_filter = filter;
}

void DependencyTreeWidget::setModel(FilterModel *model)
{
    d_model = QSharedPointer<FilterModel>(model);
    d_ui->fileListWidget->setModel(d_model.data());

    connect(model, SIGNAL(queryFailed(QString)),
            SLOT(mapperFailed(QString)));
    connect(model, SIGNAL(queryStarted(int)),
            SLOT(mapperStarted(int)));
    connect(model, SIGNAL(queryStopped(int, int)),
            SLOT(mapperStopped(int, int)));
    connect(model, SIGNAL(queryFinished(int, int, bool)),
            SLOT(mapperFinished(int, int, bool)));
    connect(model, SIGNAL(nEntriesFound(int, int)),
            SLOT(nEntriesFound(int, int)));
    connect(model, SIGNAL(progressChanged(int)),
            SLOT(progressChanged(int)));

    connect(d_ui->fileListWidget->selectionModel(),
            SIGNAL(currentChanged(QModelIndex,QModelIndex)),
            SLOT(entrySelected(QModelIndex,QModelIndex)));
}

void DependencyTreeWidget::setMacrosModel(QSharedPointer<DactMacrosModel> macrosModel)
{
    d_macrosModel = macrosModel;
    d_xpathValidator = QSharedPointer<XPathValidator>(new XPathValidator(d_macrosModel));
    d_ui->highlightLineEdit->setValidator(d_xpathValidator.data());
}

void DependencyTreeWidget::setHighlight(QString const &query)
{
    d_highlight = query;
    d_ui->highlightLineEdit->setText(query);
    showFile(); // to force-reload the tree and bracketed sentence
}

void DependencyTreeWidget::showFile()
{
    if (!d_file.isNull())
        showFile(d_file);
}

void DependencyTreeWidget::showFile(QString const &entry)
{
    // Read XML data.
    if (d_corpusReader.isNull())
        return;

    try {
        QString xml;
        if (d_highlight.trimmed().isEmpty())
            xml = QString::fromUtf8(d_corpusReader->read(entry.toUtf8().constData()).c_str());
        else {
            ac::CorpusReader::MarkerQuery query(d_macrosModel->expand(d_highlight).toUtf8().constData(),
                                                "active", "1");
            std::list<ac::CorpusReader::MarkerQuery> queries;
            queries.push_back(query);
            xml = QString::fromUtf8(d_corpusReader->read(entry.toUtf8().constData(), queries).c_str());
        }

        if (xml.size() == 0) {
            qWarning() << "MainWindow::writeSettings: empty XML data!";
            d_ui->treeGraphicsView->setScene(0);
            return;
        }

        // Remember file for when we need to redraw the tree
        d_file = entry;

        // Parameters
        QString valStr = d_highlight.trimmed().isEmpty() ? "'/..'" :
        QString("'") + d_macrosModel->expand(d_highlight) + QString("'");
        QHash<QString, QString> params;
        params["expr"] = valStr;

        try {
            showTree(xml);
            showSentence(entry, d_highlight);

            // I try to find my file back in the file list to keep the list
            // in sync with the treegraph since showFile can be called from
            // the child dialogs.

            QModelIndexList matches =
              d_ui->fileListWidget->model()->match(
                  d_ui->fileListWidget->model()->index(0, 0),
                  Qt::DisplayRole, entry, 1,
                  Qt::MatchFixedString | Qt::MatchCaseSensitive);
            if (matches.size() > 0) {
              d_ui->fileListWidget->selectionModel()->select(matches.at(0),
                  QItemSelectionModel::ClearAndSelect);
              d_ui->fileListWidget->scrollTo(matches.at(0));
            }
        } catch (std::runtime_error const &e) {
            QMessageBox::critical(this, QString("Tranformation error"),
                                  QString("A transformation error occured: %1\n\nCorpus data is probably corrupt.").arg(e.what()));
        }
    }
    catch(std::runtime_error const &e)
    {
        QMessageBox::critical(this, QString("Read error"),
                              QString("An error occured while trying to read a corpus file: %1").arg(e.what()));
    }
}

void DependencyTreeWidget::showSentence(QString const &entry, QString const &query)
{
    d_ui->sentenceWidget->setEntry(entry, d_macrosModel->expand(query));
}

void DependencyTreeWidget::showTree(QString const &xml)
{
    d_ui->treeGraphicsView->showTree(xml);
}

void DependencyTreeWidget::switchCorpus(QSharedPointer<alpinocorpus::CorpusReader> corpusReader)
{
    d_corpusReader = corpusReader;

    d_xpathValidator->setCorpusReader(d_corpusReader);

    setModel(new FilterModel(d_corpusReader));

    QString query = d_ui->highlightLineEdit->text();
    d_ui->highlightLineEdit->clear();
    d_ui->highlightLineEdit->insert(query);

    d_model->runQuery(d_macrosModel->expand(d_filter));

    d_ui->sentenceWidget->setCorpusReader(d_corpusReader);
}

void DependencyTreeWidget::writeSettings()
{
    QSettings settings;

    // Splitter
    settings.setValue("splitterSizes", d_ui->splitter->saveState());
}

void DependencyTreeWidget::zoomIn()
{
    d_ui->treeGraphicsView->zoomIn();
}

void DependencyTreeWidget::zoomOut()
{
    d_ui->treeGraphicsView->zoomOut();
}

void DependencyTreeWidget::showToolMenu(QPoint const &position)
{
    if (!d_ui->fileListWidget->model())
        return;

    QModelIndexList rows = d_ui->fileListWidget->selectionModel()->selectedRows();
    QList<QString> selectedFiles;

    if (rows.isEmpty())
        return;

    foreach (QModelIndex const &row, rows)
        selectedFiles << row.data().toString();

    DactToolsMenu::exec(
        DactToolsModel::sharedInstance()->tools(QString::fromStdString(d_corpusReader->name())),
        selectedFiles,
        mapToGlobal(position),
        d_ui->fileListWidget->actions());
}
<|endoftext|>


<commit_before>//* This file is part of the MOOSE framework
//* https://www.mooseframework.org
//*
//* All rights reserved, see COPYRIGHT for full restrictions
//* https://github.com/idaholab/moose/blob/master/COPYRIGHT
//*
//* Licensed under LGPL 2.1, please see LICENSE for details
//* https://www.gnu.org/licenses/lgpl-2.1.html

#include "TangentialMortarMechanicalContact.h"

registerADMooseObject("MooseApp", TangentialMortarMechanicalContact);

defineADValidParams(TangentialMortarMechanicalContact,
                    ADMortarConstraint,

                    MooseEnum component("x=0 y=1 z=2");
                    params.addRequiredParam<MooseEnum>(
                        "component",
                        component,
                        "The force component constraint that this object is supplying"););

template <ComputeStage compute_stage>
TangentialMortarMechanicalContact<compute_stage>::TangentialMortarMechanicalContact(
    const InputParameters & parameters)
  : ADMortarConstraint<compute_stage>(parameters), _component(adGetParam<MooseEnum>("component"))
{
}

template <ComputeStage compute_stage>
ADReal
TangentialMortarMechanicalContact<compute_stage>::computeQpResidual(Moose::MortarType type)
{
  switch (type)
  {
    case Moose::MortarType::Slave:
      // We have taken the convention the lagrange multiplier must have the same sign as the
      // relative slip velocity of the slave face. So positive lambda indicates that force is being
      // applied in the negative direction, so we want to decrease the momentum in the system, which
      // means we want an outflow of momentum, which means we want the residual to be positive in
      // that case. Negative lambda means force is being applied in the positive direction, so we
      // want to increase momentum in the system, which means we want an inflow of momentum, which
      // means we want the residual to be negative in that case. So the sign of this residual should
      // be the same as the sign of lambda
      return _test_slave[_i][_qp] * _lambda[_qp] *
             std::abs(_tangents[_qp][0](_component) / _tangents[_qp][0].norm());

    case Moose::MortarType::Master:
      // Equal and opposite reactions so we put a negative sign here
      return -_test_master[_i][_qp] * _lambda[_qp] *
             std::abs(_tangents[_qp][0](_component) / _tangents[_qp][0].norm());

    default:
      return 0;
  }
}
<commit_msg>Ensure that the tangential lagrange multiplier acts in the correct direction<commit_after>//* This file is part of the MOOSE framework
//* https://www.mooseframework.org
//*
//* All rights reserved, see COPYRIGHT for full restrictions
//* https://github.com/idaholab/moose/blob/master/COPYRIGHT
//*
//* Licensed under LGPL 2.1, please see LICENSE for details
//* https://www.gnu.org/licenses/lgpl-2.1.html

#include "TangentialMortarMechanicalContact.h"

registerADMooseObject("MooseApp", TangentialMortarMechanicalContact);

defineADValidParams(TangentialMortarMechanicalContact,
                    ADMortarConstraint,

                    MooseEnum component("x=0 y=1 z=2");
                    params.addRequiredParam<MooseEnum>(
                        "component",
                        component,
                        "The force component constraint that this object is supplying"););

template <ComputeStage compute_stage>
TangentialMortarMechanicalContact<compute_stage>::TangentialMortarMechanicalContact(
    const InputParameters & parameters)
  : ADMortarConstraint<compute_stage>(parameters), _component(adGetParam<MooseEnum>("component"))
{
}

template <ComputeStage compute_stage>
ADReal
TangentialMortarMechanicalContact<compute_stage>::computeQpResidual(Moose::MortarType type)
{
  switch (type)
  {
    case Moose::MortarType::Slave:
      // We have taken the convention the lagrange multiplier must have the same sign as the
      // relative slip velocity of the slave face. So positive lambda indicates that force is being
      // applied in the negative direction, so we want to decrease the momentum in the system, which
      // means we want an outflow of momentum, which means we want the residual to be positive in
      // that case. Negative lambda means force is being applied in the positive direction, so we
      // want to increase momentum in the system, which means we want an inflow of momentum, which
      // means we want the residual to be negative in that case. So the sign of this residual should
      // be the same as the sign of lambda
      return _test_slave[_i][_qp] * _lambda[_qp] * _tangents[_qp][0](_component) /
             _tangents[_qp][0].norm();

    case Moose::MortarType::Master:
      // Equal and opposite reactions so we put a negative sign here
      return -_test_master[_i][_qp] * _lambda[_qp] * _tangents[_qp][0](_component) /
             _tangents[_qp][0].norm();

    default:
      return 0;
  }
}
<|endoftext|>