<commit_before>#pragma once

#include <sstream>
#include <cp/type_traits.hpp>

namespace cp { namespace diagnostics { namespace detail {

template <class T>
inline std::string to_string(const T& value);

template <class T, type_kind K = type_kind_of<T>>
struct to_string_impl : to_string_impl<T, general_type_kind_v<K>> {};

template <class T, class = decltype((std::stringstream&)(std::declval<std::stringstream>()) << std::declval<T>())>
std::true_type can_be_stringified_impl(int);

template <class T>
std::false_type can_be_stringified_impl(...);

template <class T>
static constexpr bool can_be_stringified_v = decltype(can_be_stringified_impl<T>(0))::value;

template <class T>
inline std::enable_if_t<can_be_stringified_v<T>, std::string> to_string_impl_impl(const T& value) {
    std::stringstream ss;
    ss << value;
    return ss.str();
}

template <class T>
inline std::enable_if_t<!can_be_stringified_v<T>, std::string> to_string_impl_impl(const T& value) {
    return "<unknown-type>";
}

template <class T>
struct to_string_impl<T, type_kind::unknown> {
    static std::string doit(const T& value) { return to_string_impl_impl(value); }
};

template <class T>
struct to_string_impl<T, type_kind::boolean> {
    static std::string doit(const T& value) { return value ? "true" : "false"; }
};

template <class T>
struct to_string_impl<T, type_kind::string> {
    static std::string doit(const T& value) {
        std::string res(1, '"');
        for (char c : std::string(value)) {
            switch (c) {
                case '\"': res += "\\\""; break;
                case '\n': res += "\\n" ; break;
                case '\r': res += "\\r" ; break;
                default  : res += c;
            }
        }
        return res += '"';
    }
};

template <class T>
struct to_string_impl<T, type_kind::sequence_container> {
    static std::string doit(const T& value) {
        std::string res = "[";
        bool first = true;
        for (const auto& v : value) {
            if (first) first = false;
            else res += ", ";
            res += to_string(v);
        }
        return res += "]";
    }
};

template <int N>
struct to_string_impl<char[N], type_kind::sequence_container> : to_string_impl<char[N], type_kind::string>
{
};

template <class T>
struct to_string_impl<T, type_kind::map> {
    static std::string doit(const T& value) {
        std::string res = "{";
        bool first = true;
        for (auto& kv : value) {
            if (first) first = false;
            else res += ", ";
            res += to_string(kv.first);
            res += ": ";
            res += to_string(kv.second);
        }
        return res += "}";
    }
};

template <class T>
struct to_string_impl<T, type_kind::set> {
    static std::string doit(const T& value) {
        std::string res = "{";
        bool first = true;
        for (auto& v : value) {
            if (first) first = false;
            else res += ", ";
            res += to_string(v);
        }
        return res += "}";
    }
};

template <class T>
struct to_string_impl<T, type_kind::pair> {
    static std::string doit(const T& value) {
        return "(" + to_string(value.first) + ", " + to_string(value.second) + ")";
    }
};

template <class... Ts>
struct to_string_impl<std::tuple<Ts...>, type_kind::tuple> {
    template <int... Indices>
    static std::string doit(const std::tuple<Ts...>& value, std::integer_sequence<int, Indices...>) {
        std::string tupleStr[] = {to_string(std::get<Indices>(value))...};
        std::string res(1, '(');
        for (int i = 0; i < sizeof...(Indices); ++i) {
            if (i) res += ", ";
            res += tupleStr[i];
        }
        return res += ")";
    }

    static std::string doit(const std::tuple<Ts...>& value) {
        return doit(value, std::make_integer_sequence<int, sizeof...(Ts)>());
    }
};

template <>
struct to_string_impl<std::nullptr_t, type_kind::unknown> {
    static std::string doit(std::nullptr_t) {
        return "null";
    }
};

template <class T>
inline std::string to_string(const T& value) {
    return detail::to_string_impl<T, type_kind_of<T>>::doit(value);
}

}}}  // namespace cp::diagnostics::detail
<commit_msg>Fixed include.<commit_after>#pragma once

#include <cp/type_traits.hpp>

#include <sstream>
#include <utility>

namespace cp { namespace diagnostics { namespace detail {

template <class T>
inline std::string to_string(const T& value);

template <class T, type_kind K = type_kind_of<T>>
struct to_string_impl : to_string_impl<T, general_type_kind_v<K>> {};

template <class T, class = decltype((std::stringstream&)(std::declval<std::stringstream>()) << std::declval<T>())>
std::true_type can_be_stringified_impl(int);

template <class T>
std::false_type can_be_stringified_impl(...);

template <class T>
static constexpr bool can_be_stringified_v = decltype(can_be_stringified_impl<T>(0))::value;

template <class T>
inline std::enable_if_t<can_be_stringified_v<T>, std::string> to_string_impl_impl(const T& value) {
    std::stringstream ss;
    ss << value;
    return ss.str();
}

template <class T>
inline std::enable_if_t<!can_be_stringified_v<T>, std::string> to_string_impl_impl(const T& value) {
    return "<unknown-type>";
}

template <class T>
struct to_string_impl<T, type_kind::unknown> {
    static std::string doit(const T& value) { return to_string_impl_impl(value); }
};

template <class T>
struct to_string_impl<T, type_kind::boolean> {
    static std::string doit(const T& value) { return value ? "true" : "false"; }
};

template <class T>
struct to_string_impl<T, type_kind::string> {
    static std::string doit(const T& value) {
        std::string res(1, '"');
        for (char c : std::string(value)) {
            switch (c) {
                case '\"': res += "\\\""; break;
                case '\n': res += "\\n" ; break;
                case '\r': res += "\\r" ; break;
                default  : res += c;
            }
        }
        return res += '"';
    }
};

template <class T>
struct to_string_impl<T, type_kind::sequence_container> {
    static std::string doit(const T& value) {
        std::string res = "[";
        bool first = true;
        for (const auto& v : value) {
            if (first) first = false;
            else res += ", ";
            res += to_string(v);
        }
        return res += "]";
    }
};

template <int N>
struct to_string_impl<char[N], type_kind::sequence_container> : to_string_impl<char[N], type_kind::string>
{
};

template <class T>
struct to_string_impl<T, type_kind::map> {
    static std::string doit(const T& value) {
        std::string res = "{";
        bool first = true;
        for (auto& kv : value) {
            if (first) first = false;
            else res += ", ";
            res += to_string(kv.first);
            res += ": ";
            res += to_string(kv.second);
        }
        return res += "}";
    }
};

template <class T>
struct to_string_impl<T, type_kind::set> {
    static std::string doit(const T& value) {
        std::string res = "{";
        bool first = true;
        for (auto& v : value) {
            if (first) first = false;
            else res += ", ";
            res += to_string(v);
        }
        return res += "}";
    }
};

template <class T>
struct to_string_impl<T, type_kind::pair> {
    static std::string doit(const T& value) {
        return "(" + to_string(value.first) + ", " + to_string(value.second) + ")";
    }
};

template <class... Ts>
struct to_string_impl<std::tuple<Ts...>, type_kind::tuple> {
    template <int... Indices>
    static std::string doit(const std::tuple<Ts...>& value, std::integer_sequence<int, Indices...>) {
        std::string tupleStr[] = {to_string(std::get<Indices>(value))...};
        std::string res(1, '(');
        for (int i = 0; i < sizeof...(Indices); ++i) {
            if (i) res += ", ";
            res += tupleStr[i];
        }
        return res += ")";
    }

    static std::string doit(const std::tuple<Ts...>& value) {
        return doit(value, std::make_integer_sequence<int, sizeof...(Ts)>());
    }
};

template <>
struct to_string_impl<std::nullptr_t, type_kind::unknown> {
    static std::string doit(std::nullptr_t) {
        return "null";
    }
};

template <class T>
inline std::string to_string(const T& value) {
    return detail::to_string_impl<T, type_kind_of<T>>::doit(value);
}

}}}  // namespace cp::diagnostics::detail
<|endoftext|>


<commit_before>/**
 * Author(s):
 *  - Herve CUCHE <hcuche@aldebaran-robotics.com>
 *
 * Copyright (C) 2011 Aldebaran Robotics
 */

/** @file
 *  @brief
 */

#pragma once
#ifndef _LIBQI_QI_ERROR_HPP_
#define _LIBQI_QI_ERROR_HPP_

# include <qi/macro.hpp>

# include <stdexcept>
# include <string>

namespace qi {
  namespace os {
    /** \class QiException error.hpp "qi/error.hpp"
     *  \brief Custom exception that may be thrown by QI methods.
     */
#ifdef _MSC_VER
# pragma warning( push )
# pragma warning( disable : 4251 )
#endif

    class QI_API QiException : public std::runtime_error
    {
    public:
      /**
       * \brief Constructor
       *
       * Create a message exception.
       *
       * \param message Exception message.
       */
      explicit QiException(const std::string &message)
        : std::runtime_error(message)
        , _message(message)
      {}

      /**
       * \brief Copy constructor.
       * \param message Exception message.
       */
      QiException(const QiException &e)
        : std::runtime_error(e.what())
      {}

      /** \brief Destructor */
      virtual ~QiException() throw()
      {}

      /** \brief Get the error message. */
      inline virtual const char* what() const throw ()
      {
        return _message.c_str();
      }

    private:
      /**
       * \var _message
       * \brief Exception message.
       */
      std::string _message;
#ifdef _MSC_VER
# pragma warning( pop )
#endif
    };
  }
}

#endif  // _LIBQI_QI_ERROR_HPP_
<commit_msg>fix compilation on windows<commit_after>/**
 * Author(s):
 *  - Herve CUCHE <hcuche@aldebaran-robotics.com>
 *
 * Copyright (C) 2011 Aldebaran Robotics
 */

/** @file
 *  @brief
 */

#pragma once
#ifndef _LIBQI_QI_ERROR_HPP_
#define _LIBQI_QI_ERROR_HPP_

# include <qi/macro.hpp>

# include <stdexcept>
# include <string>

namespace qi {
  namespace os {
    /** \class QiException error.hpp "qi/error.hpp"
     *  \brief Custom exception that may be thrown by QI methods.
     */
#ifdef _MSC_VER
# pragma warning( push )
# pragma warning( disable : 4251 )
#endif

    QI_API class QiException : public std::runtime_error
    {
    public:
      /**
       * \brief Constructor
       *
       * Create a message exception.
       *
       * \param message Exception message.
       */
      explicit QiException(const std::string &message)
        : std::runtime_error(message)
        , _message(message)
      {}

      /**
       * \brief Copy constructor.
       * \param message Exception message.
       */
      QiException(const QiException &e)
        : std::runtime_error(e.what())
      {}

      /** \brief Destructor */
      virtual ~QiException() throw()
      {}

      /** \brief Get the error message. */
      inline virtual const char* what() const throw ()
      {
        return _message.c_str();
      }

    private:
      /**
       * \var _message
       * \brief Exception message.
       */
      std::string _message;
#ifdef _MSC_VER
# pragma warning( pop )
#endif
    };
  }
}

#endif  // _LIBQI_QI_ERROR_HPP_
<|endoftext|>


<commit_before>/*!
 * Copyright (C) 2014 Nomovok Ltd. All rights reserved.
 * Contact: info@nomovok.com
 *
 * This file may be used under the terms of the GNU Lesser
 * General Public License version 2.1 as published by the Free Software
 * Foundation and appearing in the file LICENSE.LGPL included in the
 * packaging of this file.  Please review the following information to
 * ensure the GNU Lesser General Public License version 2.1 requirements
 * will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
 *
 * In addition, as a special exception, copyright holders
 * give you certain additional rights.  These rights are described in
 * the Digia Qt LGPL Exception version 1.1, included in the file
 * LGPL_EXCEPTION.txt in this package.
 */

#include <QCoreApplication>
#include <QFile>
#include <QDataStream>
#include <QTimer>
#include <QQmlEngine>

#include <iostream>
#include "qmlc.h"
#include "scriptc.h"
#include "comp.h"

using std::cerr;
using std::endl;

int main(int argc, char *argv[])
{
    QCoreApplication app(argc, argv);
    QQmlEngine *engine = new QQmlEngine;
    if (argc != 2) {
        cerr << "Usage: " << argv[0] << " input-file" << endl;
        return EXIT_FAILURE;
    }
    QString fileName(argv[1]);

    if (fileName.lastIndexOf('.') <= 0) {
        cerr << "Filename cannot be empty";
        return EXIT_FAILURE;
    }

    Compiler *compiler = NULL;
    if (fileName.endsWith(".js")) {
        compiler = new ScriptC(engine);
    } else if (fileName.endsWith(".qml")) {
        compiler = new QmlC(engine);
    } else {
        cerr << "Supported filetypes include .js and .qml" << endl;
        return EXIT_FAILURE;
    }
    Comp comp;
    comp.compiler = compiler;
    comp.fileName = fileName;

    /*
    QObject::connect(&comp, SIGNAL(finished()), &app, SLOT(quit()));
    QTimer::singleShot(0, &comp, SLOT(compile()));

    app.exec();
    */
    comp.compile();

    delete compiler;
    delete engine;
    if (Comp::retValue == 0)
        return EXIT_SUCCESS;
    else
        return EXIT_FAILURE;
}
<commit_msg>Add . to import path in qmc<commit_after>/*!
 * Copyright (C) 2014 Nomovok Ltd. All rights reserved.
 * Contact: info@nomovok.com
 *
 * This file may be used under the terms of the GNU Lesser
 * General Public License version 2.1 as published by the Free Software
 * Foundation and appearing in the file LICENSE.LGPL included in the
 * packaging of this file.  Please review the following information to
 * ensure the GNU Lesser General Public License version 2.1 requirements
 * will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
 *
 * In addition, as a special exception, copyright holders
 * give you certain additional rights.  These rights are described in
 * the Digia Qt LGPL Exception version 1.1, included in the file
 * LGPL_EXCEPTION.txt in this package.
 */

#include <QCoreApplication>
#include <QFile>
#include <QDataStream>
#include <QTimer>
#include <QQmlEngine>

#include <iostream>
#include "qmlc.h"
#include "scriptc.h"
#include "comp.h"

using std::cerr;
using std::endl;

int main(int argc, char *argv[])
{
    QCoreApplication app(argc, argv);
    QQmlEngine *engine = new QQmlEngine;
    if (argc != 2) {
        cerr << "Usage: " << argv[0] << " input-file" << endl;
        return EXIT_FAILURE;
    }
    QString fileName(argv[1]);

    if (fileName.lastIndexOf('.') <= 0) {
        cerr << "Filename cannot be empty";
        return EXIT_FAILURE;
    }

    // update import path to include .
    // engine->addImportPath(".");  doesn't work?
    char *curvalue = getenv("QML2_IMPORT_PATH");
    if(curvalue){
        char *newvalue = (char *)malloc(strlen(curvalue) + 2);
        if(!newvalue){
            qWarning("malloc failed, couldn't update QML_IMPORT_PATH");
        }else{
            sprintf(newvalue, "%s:%s", curvalue, ".");
            setenv("QML2_IMPORT_PATH", newvalue, 1);
            free(newvalue);
        }
    }else{
        setenv("QML2_IMPORT_PATH", ".", 1);
    }

    Compiler *compiler = NULL;
    if (fileName.endsWith(".js")) {
        compiler = new ScriptC(engine);
    } else if (fileName.endsWith(".qml")) {
        compiler = new QmlC(engine);
    } else {
        cerr << "Supported filetypes include .js and .qml" << endl;
        return EXIT_FAILURE;
    }
    Comp comp;
    comp.compiler = compiler;
    comp.fileName = fileName;

    /*
    QObject::connect(&comp, SIGNAL(finished()), &app, SLOT(quit()));
    QTimer::singleShot(0, &comp, SLOT(compile()));

    app.exec();
    */
    comp.compile();

    delete compiler;
    delete engine;
    if (Comp::retValue == 0)
        return EXIT_SUCCESS;
    else
        return EXIT_FAILURE;
}
<|endoftext|>


<commit_before>/*
 * ReferenceAnalyzer.cpp
 *
 * This file is part of the XShaderCompiler project (Copyright (c) 2014-2016 by Lukas Hermanns)
 * See "LICENSE.txt" for license information.
 */

#include "ReferenceAnalyzer.h"
#include "AST.h"

namespace Xsc
{

ReferenceAnalyzer::ReferenceAnalyzer(const ASTSymbolTable& symTable) :
    symTable_{ &symTable }
{
}

void ReferenceAnalyzer::MarkReferencesFromEntryPoint(FunctionDecl* ast, Program* program)
{
    program_ = program;
    ast->flags << FunctionDecl::isReferenced;
    Visit(ast);
}

/*
 * ======= Private: =======
 */

/* ------- Visit functions ------- */

#define IMPLEMENT_VISIT_PROC(AST_NAME) \
    void ReferenceAnalyzer::Visit##AST_NAME(AST_NAME* ast, void* args)

IMPLEMENT_VISIT_PROC(Program)
{
    for (auto& globDecl : ast->globalDecls)
        Visit(globDecl);
}

IMPLEMENT_VISIT_PROC(CodeBlock)
{
    for (auto& stmnt : ast->stmnts)
        Visit(stmnt);
}

IMPLEMENT_VISIT_PROC(FunctionCall)
{
    /* Mark this function to be referenced */
    const auto& name = ast->name->ident;
    auto symbol = symTable_->Fetch(name);

    if (symbol)
    {
        if (symbol->Type() == AST::Types::FunctionDecl)
        {
            auto functionDecl = dynamic_cast<FunctionDecl*>(symbol);
            if (functionDecl)
            {
                /* Mark all forward declarations to this function */
                for (auto& forwardDecl : functionDecl->forwardDeclsRef)
                    forwardDecl->flags << FunctionDecl::isReferenced;
            }

            /* Mark this function and visit the entire function body */
            symbol->flags << FunctionDecl::isReferenced;
            Visit(symbol);
        }
        else if (symbol->Type() == AST::Types::TextureDecl)
            MarkTextureReference(symbol, name);
    }
    else
    {
        /* Check for intrinsic usage */
        if (name == "rcp")
            program_->flags << Program::rcpIntrinsicUsed;
        else if (name == "sincos")
            program_->flags << Program::sinCosIntrinsicUsed;
        else if (name == "clip")
            program_->flags << Program::clipIntrinsicUsed;
    }

    /* Visit arguments */
    for (auto& arg : ast->arguments)
        Visit(arg);
}

IMPLEMENT_VISIT_PROC(Structure)
{
    /* Check if this function was already marked by this analyzer */
    if (!ast->flags(FunctionDecl::wasMarked))
    {
        ast->flags << FunctionDecl::wasMarked;

        /* Mark this structure to be referenced */
        ast->flags << Structure::isReferenced;

        /* Analyze structure members */
        for (auto& member : ast->members)
            Visit(member);
    }
}

IMPLEMENT_VISIT_PROC(SwitchCase)
{
    Visit(ast->expr);
    for (auto& stmnt : ast->stmnts)
        Visit(stmnt);
}

/* --- Global declarations --- */

IMPLEMENT_VISIT_PROC(FunctionDecl)
{
    /* Check if this function was already marked by this analyzer */
    if (!ast->flags(FunctionDecl::wasMarked))
    {
        ast->flags << FunctionDecl::wasMarked;

        /* Analyze function */
        Visit(ast->returnType);
        for (auto& param : ast->parameters)
            Visit(param);
        Visit(ast->codeBlock);
    }
}

IMPLEMENT_VISIT_PROC(UniformBufferDecl)
{
    /* Check if this function was already marked by this analyzer */
    if (!ast->flags(UniformBufferDecl::wasMarked))
    {
        ast->flags << UniformBufferDecl::wasMarked;

        /* Analyze uniform buffer */
        ast->flags << UniformBufferDecl::isReferenced;

        for (auto& member : ast->members)
            Visit(member);
    }
}

IMPLEMENT_VISIT_PROC(StructDecl)
{
    Visit(ast->structure);
}

/* --- Statements --- */

IMPLEMENT_VISIT_PROC(CodeBlockStmnt)
{
    Visit(ast->codeBlock);
}

IMPLEMENT_VISIT_PROC(ForLoopStmnt)
{
    Visit(ast->initSmnt);
    Visit(ast->condition);
    Visit(ast->iteration);
    Visit(ast->bodyStmnt);
}

IMPLEMENT_VISIT_PROC(WhileLoopStmnt)
{
    Visit(ast->condition);
    Visit(ast->bodyStmnt);
}

IMPLEMENT_VISIT_PROC(DoWhileLoopStmnt)
{
    Visit(ast->bodyStmnt);
    Visit(ast->condition);
}

IMPLEMENT_VISIT_PROC(IfStmnt)
{
    Visit(ast->condition);
    Visit(ast->bodyStmnt);
    Visit(ast->elseStmnt);
}

IMPLEMENT_VISIT_PROC(ElseStmnt)
{
    Visit(ast->bodyStmnt);
}

IMPLEMENT_VISIT_PROC(SwitchStmnt)
{
    Visit(ast->selector);

    for (auto& switchCase : ast->cases)
        Visit(switchCase);
}

IMPLEMENT_VISIT_PROC(VarDeclStmnt)
{
    Visit(ast->varType);
    for (auto& varDecl : ast->varDecls)
        Visit(varDecl);
}

IMPLEMENT_VISIT_PROC(AssignStmnt)
{
    Visit(ast->expr);
}

IMPLEMENT_VISIT_PROC(FunctionCallStmnt)
{
    Visit(ast->call);
}

IMPLEMENT_VISIT_PROC(ReturnStmnt)
{
    Visit(ast->expr);
}

/* --- Expressions --- */

IMPLEMENT_VISIT_PROC(ListExpr)
{
    Visit(ast->firstExpr);
    Visit(ast->nextExpr);
}

IMPLEMENT_VISIT_PROC(BinaryExpr)
{
    Visit(ast->lhsExpr);
    Visit(ast->rhsExpr);
}

IMPLEMENT_VISIT_PROC(UnaryExpr)
{
    Visit(ast->expr);
}

IMPLEMENT_VISIT_PROC(PostUnaryExpr)
{
    Visit(ast->expr);
}

IMPLEMENT_VISIT_PROC(FunctionCallExpr)
{
    Visit(ast->call);
    Visit(ast->varIdentSuffix);
}

IMPLEMENT_VISIT_PROC(BracketExpr)
{
    Visit(ast->expr);
}

IMPLEMENT_VISIT_PROC(CastExpr)
{
    Visit(ast->expr);
}

IMPLEMENT_VISIT_PROC(VarAccessExpr)
{
    /* Mark texture reference */
    auto symbol = symTable_->Fetch(ast->varIdent->ident);
    if (symbol)
    {
        if (symbol->Type() == AST::Types::TextureDecl)
            MarkTextureReference(symbol, ast->varIdent->ident);
        else if (symbol->Type() == AST::Types::VarDecl)
        {
            auto varDecl = dynamic_cast<VarDecl*>(symbol);
            if (varDecl && varDecl->uniformBufferRef)
                Visit(varDecl->uniformBufferRef);
        }
    }

    Visit(ast->assignExpr);
}

IMPLEMENT_VISIT_PROC(InitializerExpr)
{
    for (auto& expr : ast->exprs)
        Visit(expr);
}

/* --- Variables --- */

IMPLEMENT_VISIT_PROC(VarType)
{
    if (!ast->baseType.empty())
    {
        auto symbol = symTable_->Fetch(ast->baseType);
        if (symbol)
            Visit(symbol);
    }
    else if (ast->structType)
        Visit(ast->structType);
}

IMPLEMENT_VISIT_PROC(VarIdent)
{
    for (auto& index : ast->arrayIndices)
        Visit(index);
    Visit(ast->next);
}

IMPLEMENT_VISIT_PROC(VarDecl)
{
    for (auto& dim : ast->arrayDims)
        Visit(dim);
    Visit(ast->initializer);
}

#undef IMPLEMENT_VISIT_PROC

/* --- Helper functions for analysis --- */

void ReferenceAnalyzer::MarkTextureReference(AST* ast, const std::string& texIdent)
{
    ast->flags << TextureDecl::isReferenced;

    auto texDecl = dynamic_cast<TextureDecl*>(ast);
    if (texDecl)
    {
        /* Mark individual texture identifier to be used */
        for (auto& tex : texDecl->names)
        {
            if (tex->ident == texIdent)
            {
                tex->flags << BufferDeclIdent::isReferenced;
                break;
            }
        }
    }
}

} // /namespace Xsc

// ================================================================================<commit_msg>Fixed typo.<commit_after>/*
 * ReferenceAnalyzer.cpp
 *
 * This file is part of the XShaderCompiler project (Copyright (c) 2014-2016 by Lukas Hermanns)
 * See "LICENSE.txt" for license information.
 */

#include "ReferenceAnalyzer.h"
#include "AST.h"

namespace Xsc
{

ReferenceAnalyzer::ReferenceAnalyzer(const ASTSymbolTable& symTable) :
    symTable_{ &symTable }
{
}

void ReferenceAnalyzer::MarkReferencesFromEntryPoint(FunctionDecl* ast, Program* program)
{
    program_ = program;
    ast->flags << FunctionDecl::isReferenced;
    Visit(ast);
}

/*
 * ======= Private: =======
 */

/* ------- Visit functions ------- */

#define IMPLEMENT_VISIT_PROC(AST_NAME) \
    void ReferenceAnalyzer::Visit##AST_NAME(AST_NAME* ast, void* args)

IMPLEMENT_VISIT_PROC(Program)
{
    for (auto& globDecl : ast->globalDecls)
        Visit(globDecl);
}

IMPLEMENT_VISIT_PROC(CodeBlock)
{
    for (auto& stmnt : ast->stmnts)
        Visit(stmnt);
}

IMPLEMENT_VISIT_PROC(FunctionCall)
{
    /* Mark this function to be referenced */
    const auto& name = ast->name->ident;
    auto symbol = symTable_->Fetch(name);

    if (symbol)
    {
        if (symbol->Type() == AST::Types::FunctionDecl)
        {
            auto functionDecl = dynamic_cast<FunctionDecl*>(symbol);
            if (functionDecl)
            {
                /* Mark all forward declarations to this function */
                for (auto& forwardDecl : functionDecl->forwardDeclsRef)
                    forwardDecl->flags << FunctionDecl::isReferenced;
            }

            /* Mark this function and visit the entire function body */
            symbol->flags << FunctionDecl::isReferenced;
            Visit(symbol);
        }
        else if (symbol->Type() == AST::Types::TextureDecl)
            MarkTextureReference(symbol, name);
    }
    else
    {
        /* Check for intrinsic usage */
        if (name == "rcp")
            program_->flags << Program::rcpIntrinsicUsed;
        else if (name == "sincos")
            program_->flags << Program::sinCosIntrinsicUsed;
        else if (name == "clip")
            program_->flags << Program::clipIntrinsicUsed;
    }

    /* Visit arguments */
    for (auto& arg : ast->arguments)
        Visit(arg);
}

IMPLEMENT_VISIT_PROC(Structure)
{
    /* Check if this function was already marked by this analyzer */
    if (!ast->flags(Structure::wasMarked))
    {
        ast->flags << Structure::wasMarked;

        /* Mark this structure to be referenced */
        ast->flags << Structure::isReferenced;

        /* Analyze structure members */
        for (auto& member : ast->members)
            Visit(member);
    }
}

IMPLEMENT_VISIT_PROC(SwitchCase)
{
    Visit(ast->expr);
    for (auto& stmnt : ast->stmnts)
        Visit(stmnt);
}

/* --- Global declarations --- */

IMPLEMENT_VISIT_PROC(FunctionDecl)
{
    /* Check if this function was already marked by this analyzer */
    if (!ast->flags(FunctionDecl::wasMarked))
    {
        ast->flags << FunctionDecl::wasMarked;

        /* Analyze function */
        Visit(ast->returnType);
        for (auto& param : ast->parameters)
            Visit(param);
        Visit(ast->codeBlock);
    }
}

IMPLEMENT_VISIT_PROC(UniformBufferDecl)
{
    /* Check if this function was already marked by this analyzer */
    if (!ast->flags(UniformBufferDecl::wasMarked))
    {
        ast->flags << UniformBufferDecl::wasMarked;

        /* Analyze uniform buffer */
        ast->flags << UniformBufferDecl::isReferenced;

        for (auto& member : ast->members)
            Visit(member);
    }
}

IMPLEMENT_VISIT_PROC(StructDecl)
{
    Visit(ast->structure);
}

/* --- Statements --- */

IMPLEMENT_VISIT_PROC(CodeBlockStmnt)
{
    Visit(ast->codeBlock);
}

IMPLEMENT_VISIT_PROC(ForLoopStmnt)
{
    Visit(ast->initSmnt);
    Visit(ast->condition);
    Visit(ast->iteration);
    Visit(ast->bodyStmnt);
}

IMPLEMENT_VISIT_PROC(WhileLoopStmnt)
{
    Visit(ast->condition);
    Visit(ast->bodyStmnt);
}

IMPLEMENT_VISIT_PROC(DoWhileLoopStmnt)
{
    Visit(ast->bodyStmnt);
    Visit(ast->condition);
}

IMPLEMENT_VISIT_PROC(IfStmnt)
{
    Visit(ast->condition);
    Visit(ast->bodyStmnt);
    Visit(ast->elseStmnt);
}

IMPLEMENT_VISIT_PROC(ElseStmnt)
{
    Visit(ast->bodyStmnt);
}

IMPLEMENT_VISIT_PROC(SwitchStmnt)
{
    Visit(ast->selector);

    for (auto& switchCase : ast->cases)
        Visit(switchCase);
}

IMPLEMENT_VISIT_PROC(VarDeclStmnt)
{
    Visit(ast->varType);
    for (auto& varDecl : ast->varDecls)
        Visit(varDecl);
}

IMPLEMENT_VISIT_PROC(AssignStmnt)
{
    Visit(ast->expr);
}

IMPLEMENT_VISIT_PROC(FunctionCallStmnt)
{
    Visit(ast->call);
}

IMPLEMENT_VISIT_PROC(ReturnStmnt)
{
    Visit(ast->expr);
}

/* --- Expressions --- */

IMPLEMENT_VISIT_PROC(ListExpr)
{
    Visit(ast->firstExpr);
    Visit(ast->nextExpr);
}

IMPLEMENT_VISIT_PROC(BinaryExpr)
{
    Visit(ast->lhsExpr);
    Visit(ast->rhsExpr);
}

IMPLEMENT_VISIT_PROC(UnaryExpr)
{
    Visit(ast->expr);
}

IMPLEMENT_VISIT_PROC(PostUnaryExpr)
{
    Visit(ast->expr);
}

IMPLEMENT_VISIT_PROC(FunctionCallExpr)
{
    Visit(ast->call);
    Visit(ast->varIdentSuffix);
}

IMPLEMENT_VISIT_PROC(BracketExpr)
{
    Visit(ast->expr);
}

IMPLEMENT_VISIT_PROC(CastExpr)
{
    Visit(ast->expr);
}

IMPLEMENT_VISIT_PROC(VarAccessExpr)
{
    /* Mark texture reference */
    auto symbol = symTable_->Fetch(ast->varIdent->ident);
    if (symbol)
    {
        if (symbol->Type() == AST::Types::TextureDecl)
            MarkTextureReference(symbol, ast->varIdent->ident);
        else if (symbol->Type() == AST::Types::VarDecl)
        {
            auto varDecl = dynamic_cast<VarDecl*>(symbol);
            if (varDecl && varDecl->uniformBufferRef)
                Visit(varDecl->uniformBufferRef);
        }
    }

    Visit(ast->assignExpr);
}

IMPLEMENT_VISIT_PROC(InitializerExpr)
{
    for (auto& expr : ast->exprs)
        Visit(expr);
}

/* --- Variables --- */

IMPLEMENT_VISIT_PROC(VarType)
{
    if (!ast->baseType.empty())
    {
        auto symbol = symTable_->Fetch(ast->baseType);
        if (symbol)
            Visit(symbol);
    }
    else if (ast->structType)
        Visit(ast->structType);
}

IMPLEMENT_VISIT_PROC(VarIdent)
{
    for (auto& index : ast->arrayIndices)
        Visit(index);
    Visit(ast->next);
}

IMPLEMENT_VISIT_PROC(VarDecl)
{
    for (auto& dim : ast->arrayDims)
        Visit(dim);
    Visit(ast->initializer);
}

#undef IMPLEMENT_VISIT_PROC

/* --- Helper functions for analysis --- */

void ReferenceAnalyzer::MarkTextureReference(AST* ast, const std::string& texIdent)
{
    ast->flags << TextureDecl::isReferenced;

    auto texDecl = dynamic_cast<TextureDecl*>(ast);
    if (texDecl)
    {
        /* Mark individual texture identifier to be used */
        for (auto& tex : texDecl->names)
        {
            if (tex->ident == texIdent)
            {
                tex->flags << BufferDeclIdent::isReferenced;
                break;
            }
        }
    }
}

} // /namespace Xsc

// ================================================================================<|endoftext|>


<commit_before>/* Copyright (C) 2013 Slawomir Cygan <slawomir.cygan@gmail.com>
*
* 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 "dglandroidselectdev.h"

DGLAndroidSelectDevWidget::DGLAndroidSelectDevWidget(QWidget* parent)
        : m_KillOrConnectHandler(this), QWidget(parent) {
    m_ui.setupUi(this);
    m_ReloadTimer.setInterval(1000);

    CONNASSERT(&m_ReloadTimer, SIGNAL(timeout()), this, SLOT(reloadDevices()));
}

DGLADBDevice* DGLAndroidSelectDevWidget::getCurrentDevice() {
    return m_CurrentDevice.get();
}

void DGLAndroidSelectDevWidget::adbKillServer() {

    DGLAdbCookie* cookie = DGLAdbInterface::get()->killServer(&m_KillOrConnectHandler);
    cookie->process();
}

void DGLAndroidSelectDevWidget::adbConnect() {

    if (m_ConnectDialog.exec() == QDialog::Accepted) {
        DGLAdbCookie* cookie =
                DGLAdbInterface::get()->connect(m_ConnectDialog.getAddress(), &m_KillOrConnectHandler);
        cookie->process();
    }
}

void DGLAndroidSelectDevWidget::selectDevice(const QString& serial) {
    if (m_CurrentDevice.get() &&
        m_CurrentDevice->getSerial() != serial.toStdString()) {

        m_CurrentDevice->disconnect();
        m_CurrentDevice.reset();

        emit selectDevice(nullptr);
    }
    if (serial.size()) {
        m_CurrentDevice = std::make_shared<DGLADBDevice>(serial.toStdString());
        emit selectDevice(m_CurrentDevice.get());
    }
}

void DGLAndroidSelectDevWidget::reloadDevices() {

    m_ReloadTimer.start();

    DGLAdbCookie* cookie = DGLAdbInterface::get()->getDevices(this);

    cookie->process();
}

void DGLAndroidSelectDevWidget::gotDevices(std::vector<std::string> devices) {

    std::sort(devices.begin(), devices.end());

    int j = 0;
    for (size_t i = 0; i < devices.size(); i++) {
        while (j < m_ui.comboBox->count() &&
               devices[i] < m_ui.comboBox->itemText(j).toStdString()) {
            m_ui.comboBox->removeItem(j);
        }
        if (m_ui.comboBox->itemText(j).toStdString() != devices[i]) {
            m_ui.comboBox->insertItem(j, QIcon(),
                                      QString::fromStdString(devices[i]));
        }
        j++;
    }
    while (m_ui.comboBox->count() > j) {
        m_ui.comboBox->removeItem(j);
    }
    if (m_CurrentDevice.get()) {
        emit updateWidget();
    }
}

void DGLAndroidSelectDevWidget::showEvent(QShowEvent* event) {
    reloadDevices();
    QWidget::showEvent(event);
}

void DGLAndroidSelectDevWidget::hideEvent(QHideEvent* event) {
    m_ReloadTimer.stop();
    QWidget::hideEvent(event);
}

void DGLAndroidSelectDevWidget::KillOrConnectHandler::done(const std::vector<std::string>&) {
    m_Parent->reloadDevices();
}

void DGLAndroidSelectDevWidget::KillOrConnectHandler::failed(const std::string& reason) {
    emit m_Parent->adbFailed(reason);
}

void DGLAndroidSelectDevWidget::done(const std::vector<std::string>& data) {
    gotDevices(data);
}

void DGLAndroidSelectDevWidget::failed(const std::string& reason) {
    emit adbFailed(reason);
    m_ReloadTimer.stop();
}

DGLConnectAndroidAdbDialog::DGLConnectAndroidAdbDialog() { m_ui.setupUi(this); }

DGLConnectAndroidAdbDialog::~DGLConnectAndroidAdbDialog() {}

std::string DGLConnectAndroidAdbDialog::getAddress() {
    return m_ui.lineEdit_DeviceAddress->text().toStdString();
}<commit_msg>Android GUI cleanup: avoid spamming with "adb path is not set"<commit_after>/* Copyright (C) 2013 Slawomir Cygan <slawomir.cygan@gmail.com>
*
* 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 "dglandroidselectdev.h"

DGLAndroidSelectDevWidget::DGLAndroidSelectDevWidget(QWidget* parent)
        : m_KillOrConnectHandler(this), QWidget(parent) {
    m_ui.setupUi(this);

    CONNASSERT(&m_ReloadTimer, SIGNAL(timeout()), this, SLOT(reloadDevices()));
}

DGLADBDevice* DGLAndroidSelectDevWidget::getCurrentDevice() {
    return m_CurrentDevice.get();
}

void DGLAndroidSelectDevWidget::adbKillServer() {

    DGLAdbCookie* cookie = DGLAdbInterface::get()->killServer(&m_KillOrConnectHandler);
    cookie->process();
}

void DGLAndroidSelectDevWidget::adbConnect() {

    if (m_ConnectDialog.exec() == QDialog::Accepted) {
        DGLAdbCookie* cookie =
                DGLAdbInterface::get()->connect(m_ConnectDialog.getAddress(), &m_KillOrConnectHandler);
        cookie->process();
    }
}

void DGLAndroidSelectDevWidget::selectDevice(const QString& serial) {
    if (m_CurrentDevice.get() &&
        m_CurrentDevice->getSerial() != serial.toStdString()) {

        m_CurrentDevice->disconnect();
        m_CurrentDevice.reset();

        emit selectDevice(nullptr);
    }
    if (serial.size()) {
        m_CurrentDevice = std::make_shared<DGLADBDevice>(serial.toStdString());
        emit selectDevice(m_CurrentDevice.get());
    }
}

void DGLAndroidSelectDevWidget::reloadDevices() {

    m_ReloadTimer.setInterval(1000);
    m_ReloadTimer.start();

    DGLAdbCookie* cookie = DGLAdbInterface::get()->getDevices(this);

    cookie->process();
}

void DGLAndroidSelectDevWidget::gotDevices(std::vector<std::string> devices) {

    std::sort(devices.begin(), devices.end());

    int j = 0;
    for (size_t i = 0; i < devices.size(); i++) {
        while (j < m_ui.comboBox->count() &&
               devices[i] < m_ui.comboBox->itemText(j).toStdString()) {
            m_ui.comboBox->removeItem(j);
        }
        if (m_ui.comboBox->itemText(j).toStdString() != devices[i]) {
            m_ui.comboBox->insertItem(j, QIcon(),
                                      QString::fromStdString(devices[i]));
        }
        j++;
    }
    while (m_ui.comboBox->count() > j) {
        m_ui.comboBox->removeItem(j);
    }
    if (m_CurrentDevice.get()) {
        emit updateWidget();
    }
}

void DGLAndroidSelectDevWidget::showEvent(QShowEvent* event) {
    if (!m_ReloadTimer.isActive()) {
        m_ReloadTimer.setInterval(1);
        m_ReloadTimer.start();
    }
    QWidget::showEvent(event);
}

void DGLAndroidSelectDevWidget::hideEvent(QHideEvent* event) {
    m_ReloadTimer.stop();
    QWidget::hideEvent(event);
}

void DGLAndroidSelectDevWidget::KillOrConnectHandler::done(const std::vector<std::string>&) {
    m_Parent->reloadDevices();
}

void DGLAndroidSelectDevWidget::KillOrConnectHandler::failed(const std::string& reason) {
    emit m_Parent->adbFailed(reason);
}

void DGLAndroidSelectDevWidget::done(const std::vector<std::string>& data) {
    gotDevices(data);
}

void DGLAndroidSelectDevWidget::failed(const std::string& reason) {
    m_ReloadTimer.stop();
    emit adbFailed(reason);
}

DGLConnectAndroidAdbDialog::DGLConnectAndroidAdbDialog() { m_ui.setupUi(this); }

DGLConnectAndroidAdbDialog::~DGLConnectAndroidAdbDialog() {}

std::string DGLConnectAndroidAdbDialog::getAddress() {
    return m_ui.lineEdit_DeviceAddress->text().toStdString();
}<|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))

// declaration

static void Swapvalue(RbNode *a, RbNode *b);
static void Swapcolor(RbNode *a, RbNode *b);
static RbNode *GrandFather(RbNode *e);
static RbNode *Previous(RbNode *e);
static RbNode *Next(RbNode *e);
static RbNode *Uncle(RbNode *e);
static RbNode *Brother(RbNode *e);
static bool IsleftChild(RbNode *e);
static bool IsrightChild(RbNode *e);
static int ChildNumber(RbNode *e);
static void Rotateleft(RedBlackTree *t, RbNode *e);
static void Rotateright(RedBlackTree *t, RbNode *e);
static RbNode *Find(RedBlackTree *t, int value, RbNode **father);
static void InsertCase1(RedBlackTree *t, RbNode *e);
static void InsertCase2(RedBlackTree *t, RbNode *e);
static void InsertCase3(RedBlackTree *t, RbNode *e);
static void InsertCase4(RedBlackTree *t, RbNode *e);
static void InsertCase5(RedBlackTree *t, RbNode *e);
static void EraseCase0(RedBlackTree *t, RbNode *e);
static void EraseCase0_A(RedBlackTree *t, RbNode *e);
static void EraseCase0_B(RedBlackTree *t, RbNode *e);
static void EraseCase0_C(RedBlackTree *t, RbNode *e);
static void EraseCase1(RedBlackTree *t, RbNode *e);
static void EraseCase2(RedBlackTree *t, RbNode *e);
static void EraseCase3(RedBlackTree *t, RbNode *e);
static void EraseCase4(RedBlackTree *t, RbNode *e);
static void EraseCase5(RedBlackTree *t, RbNode *e);
static void EraseCase6(RedBlackTree *t, RbNode *e);

// implementation

static void Swapvalue(RbNode *a, RbNode *b) { std::swap(a->value, b->value); }

static void Swapcolor(RbNode *a, RbNode *b) { std::swap(a->color, b->color); }

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 IsleftChild(RbNode *e) {
  if (is_nil(e->father))
    return false;
  return e->father->left == e;
}

static bool IsrightChild(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 void Free(RbNode *e) {
  if (is_nil(e))
    return;
  Free(e->left);
  Free(e->right);
  delete e;
}

static void RL(RedBlackTree *t, RbNode *e) {
  RbNode *p = e;
  RbNode *q = e->right;
  RbNode *father = e->father;

  if (father == NULL) {
    t->root = q;
  } else {
    if (father->left == p)
      father->left = q;
    else
      father->right = q;
  }

  q->father = father;
  p->father = q;

  p->right = q->left;
  if (q->left)
    q->left->father = p;
  q->left = p;
}

static void RR(RedBlackTree *t, RbNode *e) {
  RbNode *p = e;
  RbNode *q = e->left;
  RbNode *father = p->father;
  assert(q);

  if (p->father == NULL) {
    t->root = q;
  } else {
    if (father->left == p)
      father->left = q;
    else
      father->right = q;
  }
  q->father = father;
  p->father = q;

  p->left = q->right;
  if (p->left)
    p->left->father = p;
  q->right = p;
}

static void LL(RedBlackTree *t, RbNode *e) {
  RbNode *p = e;
  RbNode *q = e->right;
  RbNode *father = e->father;

  if (father == NULL) {
    t->root = q;
  } else {
    if (father->left == p)
      father->left = q;
    else
      father->right = q;
  }

  q->father = father;
  p->father = q;

  p->right = q->left;
  if (q->left)
    q->left->father = p;
  q->left = p;
}

static void LR(RedBlackTree *t, RbNode *e) {
  RbNode *p = e;
  RbNode *q = e->left;
  RbNode *father = p->father;
  assert(q);

  if (p->father == NULL) {
    t->root = q;
  } else {
    if (father->left == p)
      father->left = q;
    else
      father->right = q;
  }
  q->father = father;
  p->father = q;

  p->left = q->right;
  if (p->left)
    p->left->father = p;
  q->right = p;
}

static RbNode *Find(RedBlackTree *t, int value, RbNode **father) {
  RbNode *cur = t->root;
  while (cur) {
    if (cur->value == value)
      return cur;
    else {
      if (father != NULL)
        *father = cur;
      if (value < cur->value)
        cur = cur->left;
      else if (value > cur->value)
        cur = cur->right;
      else if (value == cur->value)
        return cur;
    }
  }
  return NULL;
}

static void InsertCase5(RedBlackTree *t, RbNode *e) {
  e->father->color = BLACK;
  GrandFather(e)->color = RED;
  if (IsleftChild(e) && IsleftChild(e->father)) {
    Rotateright(t, GrandFather(e));
  } else {
    assert(IsrightChild(e));
    assert(IsrightChild(e->father));
    Rotateleft(t, GrandFather(e));
  }
}

static void InsertCase4(RedBlackTree *t, RbNode *e) {
  if (IsrightChild(e) && IsleftChild(e->father)) {
    Rotateleft(t, e->father);
    e = e->left;
  } else if (IsleftChild(e) && IsrightChild(e->father)) {
    Rotateright(t, e->father);
    e = e->right;
  }
  InsertCase5(t, e);
}

static void InsertCase3(RedBlackTree *t, RbNode *e) {
  if (IsleftChild(e->father)) {
  }
  if (Uncle(e)->color == RED) {
    e->father->color = BLACK;
    Uncle(e)->color = BLACK;
    GrandFather(e)->color = RED;
    InsertCase1(t, GrandFather(e));
  } else {
    InsertCase4(t, e);
  }
}

static void InsertCase2(RedBlackTree *t, RbNode *e) {
  if (e->father->color == RED) {
    InsertCase3(t, e);
  }
}

static void InsertCase1(RedBlackTree *t, RbNode *e) {
  if (t->root == NULL) {
    assert(t->root == NULL);
    assert(e->father == NULL);
    e->color = BLACK;
    t->root = e;
  } else {
    InsertCase2(t, e);
  }
}

static void EraseCase0(RedBlackTree *t, RbNode *e) {
  int child_number = ChildNumber(e);
  if (child_number == 0) {
    // 删除操作 0-a
    EraseCase0_A(t, e);
  } else if (child_number == 1) {
    // 删除操作 0-b
    EraseCase0_B(t, e);
  } else if (child_number == 2) {
    // 删除操作 0-c
    EraseCase0_C(t, e);
  }
}

static void EraseCase0_A(RedBlackTree *t, RbNode *e) {
  if (e->father->left == e)
    e->father->left = NULL;
  else if (e->father->right == e)
    e->father->right = NULL;
  delete e;
}

static void EraseCase0_B(RedBlackTree *t, RbNode *e) {
  RbNode *child = e->left ? e->left : e->right;
  Swapvalue(child, e);

  // now "child" is father of "e", while "e" is child of "child"
  child->left = child->right = NULL;
  delete e;
  EraseCase1(t, child);
}

static void EraseCase0_C(RedBlackTree *t, RbNode *e) {
  RbNode *next = Next(e);
  e->value = next->value;
  EraseCase0(t, next);
}

static void EraseCase1(RedBlackTree *t, RbNode *e) {
  if (t->root != e) {
    assert(t->root != e);
    assert(e->father != NULL);
    EraseCase2(t, e);
  }
}

static void EraseCase2(RedBlackTree *t, RbNode *e) {
  if (Brother(e)->color == RED) {
    e->father->color = RED;
    Brother(e)->color = BLACK;
    if (IsleftChild(e)) {
      Rotateleft(t, e->father);
    } else if (IsrightChild(e)) {
      Rotateright(t, e->father);
    }
    // Swapcolor(e->father, Brother(e));
  }
  EraseCase3(t, e);
}

static void EraseCase3(RedBlackTree *t, RbNode *e) {
  if (e->father->color == BLACK && Brother(e)->color == BLACK &&
      Brother(e)->left->color == BLACK && Brother(e)->right->color == BLACK) {
    Brother(e)->color = RED;
    EraseCase1(t, e->father);
  } else {
    EraseCase4(t, e);
  }
}

static void EraseCase4(RedBlackTree *t, RbNode *e) {
  if (Brother(e)->color == BLACK && e->father->color == RED &&
      Brother(e)->left->color == BLACK && Brother(e)->right->color == BLACK) {
    Swapcolor(e->father, Brother(e));
  } else {
    EraseCase5(t, e);
  }
}

static void EraseCase5(RedBlackTree *t, RbNode *e) {
  if (IsleftChild(e) && Brother(e)->color == BLACK &&
      Brother(e)->left->color == RED && Brother(e)->right->color == BLACK) {
    Swapcolor(Brother(e), Brother(e)->left);
    Rotateright(t, Brother(e));
  } else if (IsrightChild(e) && Brother(e)->color == BLACK &&
             Brother(e)->right->color == RED &&
             Brother(e)->left->color == BLACK) {
    Swapcolor(Brother(e), Brother(e)->right);
    Rotateleft(t, Brother(e));
  }
  EraseCase6(t, e);
}

static void EraseCase6(RedBlackTree *t, RbNode *e) {
  Swapcolor(Brother(e), e->father);
  if (IsleftChild(e)) {
    assert(Brother(e)->right->color == RED);
    Brother(e)->right->color = BLACK;
    Rotateleft(t, e->father);
  } else {
    assert(Brother(e)->left->color == RED);
    Brother(e)->left->color = BLACK;
    Rotateright(t, e->father);
  }
}

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

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

void RedBlackTreeInsert(RedBlackTree *t, int value) {
  RbNode *e = new RbNode();
  RbNode *father = NULL;
  RbNode *tmp;
  tmp = Find(t, value, &father);
  assert(tmp == NULL);
  e->color = RED;
  e->value = value;
  e->left = NULL;
  e->right = NULL;
  e->father = father;
  if (father) {
    if (value < father->value)
      father->left = e;
    else
      father->right = e;
  }
  // fix rbtree from e
  InsertCase1(t, e);
}

int RedBlackTreeFind(RedBlackTree *t, int value) {
  return Find(t, value, NULL) ? 1 : 0;
}

void RedBlackTreeErase(RedBlackTree *t, int value) {
  RbNode *e = Find(t, value, NULL);
  assert(e);
  EraseCase0(t, 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))

// declaration

static RbNode *Find(RedBlackTree *t, int value, RbNode **father);

static void InsertCase1(RedBlackTree *t, RbNode *e);
static void InsertCase2(RedBlackTree *t, RbNode *e);
static void InsertCase3(RedBlackTree *t, RbNode *e);
static void InsertCase4(RedBlackTree *t, RbNode *e);
static void InsertCase5(RedBlackTree *t, RbNode *e);
static void EraseCase0(RedBlackTree *t, RbNode *e);
static void EraseCase0_A(RedBlackTree *t, RbNode *e);
static void EraseCase0_B(RedBlackTree *t, RbNode *e);
static void EraseCase0_C(RedBlackTree *t, RbNode *e);
static void EraseCase1(RedBlackTree *t, RbNode *e);
static void EraseCase2(RedBlackTree *t, RbNode *e);
static void EraseCase3(RedBlackTree *t, RbNode *e);
static void EraseCase4(RedBlackTree *t, RbNode *e);
static void EraseCase5(RedBlackTree *t, RbNode *e);
static void EraseCase6(RedBlackTree *t, RbNode *e);

// implementation

static void Swapvalue(RbNode *a, RbNode *b) { std::swap(a->value, b->value); }

static void Swapcolor(RbNode *a, RbNode *b) { std::swap(a->color, b->color); }

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 RedUncle(RedBlackTree *t, RbNode *e) {}

static void RL(RedBlackTree *t, RbNode *e) {
  RbNode *p = e;
  RbNode *q = e->right;
  RbNode *father = e->father;

  if (father == NULL) {
    t->root = q;
  } else {
    if (father->left == p)
      father->left = q;
    else
      father->right = q;
  }

  q->father = father;
  p->father = q;

  p->right = q->left;
  if (q->left)
    q->left->father = p;
  q->left = p;
}

static void RR(RedBlackTree *t, RbNode *e) {
  RbNode *p = e;
  RbNode *q = e->left;
  RbNode *father = p->father;
  assert(q);

  if (p->father == NULL) {
    t->root = q;
  } else {
    if (father->left == p)
      father->left = q;
    else
      father->right = q;
  }
  q->father = father;
  p->father = q;

  p->left = q->right;
  if (p->left)
    p->left->father = p;
  q->right = p;
}

static RbNode *LL(RbNode *e) {
  RbNode *father = e->father;
  RbNode *grand_father = GrandFather(e);
  RbNode *uncle = Uncle(e);

  RbNode *p = father->right;

  father->right = grand_father;
  grand_father->left = p;

  return father;
}

static void LR(RedBlackTree *t, RbNode *e) {
  RbNode *p = e;
  RbNode *q = e->left;
  RbNode *father = p->father;
  assert(q);

  if (p->father == NULL) {
    t->root = q;
  } else {
    if (father->left == p)
      father->left = q;
    else
      father->right = q;
  }
  q->father = father;
  p->father = q;

  p->left = q->right;
  if (p->left)
    p->left->father = p;
  q->right = p;
}

static RbNode *Find(RedBlackTree *t, int value, RbNode **father) {
  RbNode *cur = t->root;
  while (cur) {
    if (cur->value == value)
      return cur;
    else {
      if (father != NULL)
        *father = cur;
      if (value < cur->value)
        cur = cur->left;
      else if (value > cur->value)
        cur = cur->right;
      else if (value == cur->value)
        return cur;
    }
  }
  return NULL;
}

static void InsertCase5(RedBlackTree *t, RbNode *e) {
  e->father->color = BLACK;
  GrandFather(e)->color = RED;
  if (IsLeft(e) && IsLeft(e->father)) {
    Rotateright(t, GrandFather(e));
  } else {
    assert(IsRight(e));
    assert(IsRight(e->father));
    Rotateleft(t, GrandFather(e));
  }
}

static void InsertCase4(RedBlackTree *t, RbNode *e) {
  if (IsRight(e) && IsLeft(e->father)) {
    Rotateleft(t, e->father);
    e = e->left;
  } else if (IsLeft(e) && IsRight(e->father)) {
    Rotateright(t, e->father);
    e = e->right;
  }
  InsertCase5(t, e);
}

static void InsertCase3(RedBlackTree *t, RbNode *e) {
  if (IsLeft(e->father)) {
  }
  if (Uncle(e)->color == RED) {
    e->father->color = BLACK;
    Uncle(e)->color = BLACK;
    GrandFather(e)->color = RED;
    InsertCase1(t, GrandFather(e));
  } else {
    InsertCase4(t, e);
  }
}

static void InsertCase2(RedBlackTree *t, RbNode *e) {
  if (e->father->color == RED) {
    InsertCase3(t, e);
  }
}

static void InsertCase1(RedBlackTree *t, RbNode *e) {
  if (t->root == NULL) {
    assert(t->root == NULL);
    assert(e->father == NULL);
    e->color = BLACK;
    t->root = e;
  } else {
    InsertCase2(t, e);
  }
}

static void EraseCase0(RedBlackTree *t, RbNode *e) {
  int child_number = ChildNumber(e);
  if (child_number == 0) {
    // 删除操作 0-a
    EraseCase0_A(t, e);
  } else if (child_number == 1) {
    // 删除操作 0-b
    EraseCase0_B(t, e);
  } else if (child_number == 2) {
    // 删除操作 0-c
    EraseCase0_C(t, e);
  }
}

static void EraseCase0_A(RedBlackTree *t, RbNode *e) {
  if (e->father->left == e)
    e->father->left = NULL;
  else if (e->father->right == e)
    e->father->right = NULL;
  delete e;
}

static void EraseCase0_B(RedBlackTree *t, RbNode *e) {
  RbNode *child = e->left ? e->left : e->right;
  Swapvalue(child, e);

  // now "child" is father of "e", while "e" is child of "child"
  child->left = child->right = NULL;
  delete e;
  EraseCase1(t, child);
}

static void EraseCase0_C(RedBlackTree *t, RbNode *e) {
  RbNode *next = Next(e);
  e->value = next->value;
  EraseCase0(t, next);
}

static void EraseCase1(RedBlackTree *t, RbNode *e) {
  if (t->root != e) {
    assert(t->root != e);
    assert(e->father != NULL);
    EraseCase2(t, e);
  }
}

static void EraseCase2(RedBlackTree *t, RbNode *e) {
  if (Brother(e)->color == RED) {
    e->father->color = RED;
    Brother(e)->color = BLACK;
    if (IsLeft(e)) {
      Rotateleft(t, e->father);
    } else if (IsRight(e)) {
      Rotateright(t, e->father);
    }
    // Swapcolor(e->father, Brother(e));
  }
  EraseCase3(t, e);
}

static void EraseCase3(RedBlackTree *t, RbNode *e) {
  if (e->father->color == BLACK && Brother(e)->color == BLACK &&
      Brother(e)->left->color == BLACK && Brother(e)->right->color == BLACK) {
    Brother(e)->color = RED;
    EraseCase1(t, e->father);
  } else {
    EraseCase4(t, e);
  }
}

static void EraseCase4(RedBlackTree *t, RbNode *e) {
  if (Brother(e)->color == BLACK && e->father->color == RED &&
      Brother(e)->left->color == BLACK && Brother(e)->right->color == BLACK) {
    Swapcolor(e->father, Brother(e));
  } else {
    EraseCase5(t, e);
  }
}

static void EraseCase5(RedBlackTree *t, RbNode *e) {
  if (IsLeft(e) && Brother(e)->color == BLACK &&
      Brother(e)->left->color == RED && Brother(e)->right->color == BLACK) {
    Swapcolor(Brother(e), Brother(e)->left);
    Rotateright(t, Brother(e));
  } else if (IsRight(e) && Brother(e)->color == BLACK &&
             Brother(e)->right->color == RED &&
             Brother(e)->left->color == BLACK) {
    Swapcolor(Brother(e), Brother(e)->right);
    Rotateleft(t, Brother(e));
  }
  EraseCase6(t, e);
}

static void EraseCase6(RedBlackTree *t, RbNode *e) {
  Swapcolor(Brother(e), e->father);
  if (IsLeft(e)) {
    assert(Brother(e)->right->color == RED);
    Brother(e)->right->color = BLACK;
    Rotateleft(t, e->father);
  } else {
    assert(Brother(e)->left->color == RED);
    Brother(e)->left->color = BLACK;
    Rotateright(t, e->father);
  }
}

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

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

void RedBlackTreeInsert(RedBlackTree *t, int value) {
  RbNode *e = new RbNode();
  RbNode *father = NULL;
  RbNode *tmp;
  tmp = Find(t, value, &father);
  assert(tmp == NULL);
  e->color = RED;
  e->value = value;
  e->left = NULL;
  e->right = NULL;
  e->father = father;
  if (father) {
    if (value < father->value)
      father->left = e;
    else
      father->right = e;
  }
  // fix rbtree from e
  InsertCase1(t, e);
}

int RedBlackTreeFind(RedBlackTree *t, int value) {
  return Find(t, value, NULL) ? 1 : 0;
}

void RedBlackTreeErase(RedBlackTree *t, int value) {
  RbNode *e = Find(t, value, NULL);
  assert(e);
  EraseCase0(t, e);
}

<|endoftext|>


<commit_before>//A triangulation routine based on Tipper's convex hull algorithm
//Computers and geoscience vol17 no 5 pp 597-632,1991
//Scaling is nlogn for random datasets
//Mike Bithell 31/08/01

// test code for triangulation

#include <math.h>
#include <fstream.h>
#include <stdlib.h>
#include <assert.h>

#include "hulltr_e.h"
#include "hulltr_test.h"

void test_ccwedge(int nedges, edge* edges){
  // test ccw edge code
  for(int iedge=0; iedge<nedges; iedge++){
    const oriented_edge e1(iedge,true);
    const oriented_edge ccw_from = e1.ccw_edge_around_from(edges);
    const oriented_edge e2(iedge,false);
    const oriented_edge ccw_to = e2.ccw_edge_around_from(edges);
#if 0
    cout << "edge=" << iedge
	 << " ret=" << edges[iedge].ret
	 << " lef=" << edges[iedge].lef
	 << " ccw_from=" << ccw_from.e()
	 << " ccw_to=" << ccw_to.e()
	 << endl;
#endif
  }
}

void sanity_check_edge(edge *edges){
  // some sanity check
  int i=0;
  while(edges[i].from != -1 ) {
    int leftp = -1,rightp = -1;
    {
      const int from = edges[i].from;
      const int lef = edges[i].lef;
      const int ref = edges[i].ref;
      if (lef != -1) {
	if (edges[lef].from==from) leftp=edges[lef].to; else leftp=edges[lef].from;
      }
      if (ref != -1) {
	if (edges[ref].from==from) rightp=edges[ref].to; else rightp=edges[ref].from;
      }
    }
    int leftp2 = -1,rightp2 = -1;
    {
      const int to = edges[i].to;
      const int let = edges[i].let;
      const int ret = edges[i].ret;
      if (let != -1) {
	if (edges[let].to==to) leftp2=edges[let].from; else leftp2=edges[let].to;
      }
      if (ret != -1) {
	if (edges[ret].to==to) rightp2=edges[ret].from; else rightp2=edges[ret].to;
      }
    }
    //cout << i
    //   << " " << leftp << " " << leftp2 << " " << rightp << " " << rightp2
    //   << endl;
    assert(leftp==leftp2);
    if (rightp!=rightp2) {
      cout << "ERR edge=" << i
	   << " pto=" << edges[i].to << " pfrom=" << edges[i].from
	   << " left(from)=" << leftp << " left(to)=" << leftp2
	   << " righp(from)=" << rightp << " rightp(to)=" << rightp2
	   << endl;
    } else {
#if 0
      cout << "edge=" << i
	   << " pto=" << edges[i].to << " pfrom=" << edges[i].from
	   << " left(from)=" << leftp << " left(to)=" << leftp2
	   << " righp(from)=" << rightp << " rightp(to)=" << rightp2
	   << endl;
#endif
    }
    assert(rightp==rightp2);

    i++;
  }
}

void write_point(int npoints, point* p)
{
  ofstream file("points_sorted");
  file << npoints << endl;
  for(int i=0;i<npoints;++i){
    p[i].write(file);
  }
}
void write_edge(edge *edges, point* p)
{
  ofstream file("triggy");
  int i=0;
  while(edges[i].from != -1 ){
    edges[i].write(file,p);
    file << "edge=" << i
	 << " pfrom=" << edges[i].from << " pto=" << edges[i].to
	 << " let=" << edges[i].let << " lef=" << edges[i].lef
	 << " ret=" << edges[i].ret << " ref=" << edges[i].ref
	 << endl;
    i++;
  }
}

//#define WRITE_FILES

void test_sort_triangulate(int npoints, point *p){
  int nedges;
  edge* edges = NULL;

  sort_triangulate(npoints,p,&nedges,&edges);

#if defined(WRITE_FILES)
  write_point(npoints, p);
#endif
#if defined(WRITE_FILES)
  write_edge(edges, p);
#endif

  sanity_check_edge(edges);
  test_ccwedge(nedges, edges);

  int nelem;
  elem* elems = NULL;

  build_elem_table(npoints, p, nedges, edges, &nelem, &elems);
  cout << "nelem=" << nelem << endl;

  delete [] elems;

  delete [] edges;
}

void generate_dataset(int n,point* p){
  //make a set of points perturbed from a uniform grid
  srand(0);
  for (int i=0;i<n;i++){
    for(int j=0;j<n;j++){
      p[i+j*n].x=double(i)+double(rand())/RAND_MAX*n*1.e-3;
      p[i+j*n].y=double(j)+double(rand())/RAND_MAX*n*1.e-3;
    }
  }
#if defined(WRITE_FILES)
  {
    const long npoints=n*n;
    ofstream file("points_res");
    file << npoints << endl;
    for(int i=0;i<npoints;++i){
      p[i].write(file);
    }
  }
#endif
}

void test_triangulate_random(int n){
  const long npoints=n*n;
  //set up the point array
  point *p = new point[npoints];
  generate_dataset(n,p);

  test_sort_triangulate(npoints,p);

  delete [] p;
}

void test_triangulate_from_file(){
  long npoints;
  ifstream file("points");
  file >> npoints;
  point *p = new point[npoints];
  for(int i=0;i<npoints;++i){
    file >> p[i].x;
    file >> p[i].y;
  }

  test_sort_triangulate(npoints,p);

  delete [] p;
}

#if defined(USE_MAIN)
int main(void){
# if 1
#   if 0
  int n=3;
  cout << "n= " << n << endl;
  test_triangulate_random(n);

#   else
  for(int n=2; n!=100; n++){
    cout << "n= " << n << endl;
    test_triangulate_random(n);
  }
#   endif
# else
  test_triangulate_from_file();
# endif
}
#endif
<commit_msg>test for ccwedge<commit_after>//A triangulation routine based on Tipper's convex hull algorithm
//Computers and geoscience vol17 no 5 pp 597-632,1991
//Scaling is nlogn for random datasets
//Mike Bithell 31/08/01

// test code for triangulation

#include <math.h>
#include <fstream.h>
#include <stdlib.h>
#include <assert.h>

#include "hulltr_e.h"
#include "hulltr_test.h"

void sanity_check_ccwedge(int nedges, const edge* edges){
  // test ccw edge code
  for(int iedge=0; iedge<nedges; iedge++){
    const oriented_edge e1(iedge,true);
    const oriented_edge ccw_from = e1.ccw_edge_around_from(edges);
    if (ccw_from.o())
      assert( edges[iedge].from == edges[ccw_from.e()].from);
    else
      assert( edges[iedge].from == edges[ccw_from.e()].to);

    const oriented_edge e2(iedge,false);
    const oriented_edge ccw_to = e2.ccw_edge_around_from(edges);
    if (ccw_to.o())
      assert( edges[iedge].to == edges[ccw_to.e()].from);
    else
      assert( edges[iedge].to == edges[ccw_to.e()].to);

#if 0
    cout << "edge=" << iedge
	 << " ret=" << edges[iedge].ret
	 << " lef=" << edges[iedge].lef
	 << " ccw_from=" << ccw_from.e()
	 << " ccw_to=" << ccw_to.e()
	 << endl;
#endif
  }
}

void sanity_check_edge(edge *edges){
  // some sanity check
  int i=0;
  while(edges[i].from != -1 ) {
    int leftp = -1,rightp = -1;
    {
      const int from = edges[i].from;
      const int lef = edges[i].lef;
      const int ref = edges[i].ref;
      if (lef != -1) {
	if (edges[lef].from==from) leftp=edges[lef].to; else leftp=edges[lef].from;
      }
      if (ref != -1) {
	if (edges[ref].from==from) rightp=edges[ref].to; else rightp=edges[ref].from;
      }
    }
    int leftp2 = -1,rightp2 = -1;
    {
      const int to = edges[i].to;
      const int let = edges[i].let;
      const int ret = edges[i].ret;
      if (let != -1) {
	if (edges[let].to==to) leftp2=edges[let].from; else leftp2=edges[let].to;
      }
      if (ret != -1) {
	if (edges[ret].to==to) rightp2=edges[ret].from; else rightp2=edges[ret].to;
      }
    }
    //cout << i
    //   << " " << leftp << " " << leftp2 << " " << rightp << " " << rightp2
    //   << endl;
    assert(leftp==leftp2);
    if (rightp!=rightp2) {
      cout << "ERR edge=" << i
	   << " pto=" << edges[i].to << " pfrom=" << edges[i].from
	   << " left(from)=" << leftp << " left(to)=" << leftp2
	   << " righp(from)=" << rightp << " rightp(to)=" << rightp2
	   << endl;
    } else {
#if 0
      cout << "edge=" << i
	   << " pto=" << edges[i].to << " pfrom=" << edges[i].from
	   << " left(from)=" << leftp << " left(to)=" << leftp2
	   << " righp(from)=" << rightp << " rightp(to)=" << rightp2
	   << endl;
#endif
    }
    assert(rightp==rightp2);

    i++;
  }
}

void write_point(int npoints, point* p)
{
  ofstream file("points_sorted");
  file << npoints << endl;
  for(int i=0;i<npoints;++i){
    p[i].write(file);
  }
}
void write_edge(edge *edges, point* p)
{
  ofstream file("triggy");
  int i=0;
  while(edges[i].from != -1 ){
    edges[i].write(file,p);
    file << "edge=" << i
	 << " pfrom=" << edges[i].from << " pto=" << edges[i].to
	 << " let=" << edges[i].let << " lef=" << edges[i].lef
	 << " ret=" << edges[i].ret << " ref=" << edges[i].ref
	 << endl;
    i++;
  }
}

//#define WRITE_FILES

void test_sort_triangulate(int npoints, point *p){
  int nedges;
  edge* edges = NULL;

  sort_triangulate(npoints,p,&nedges,&edges);

#if defined(WRITE_FILES)
  write_point(npoints, p);
#endif
#if defined(WRITE_FILES)
  write_edge(edges, p);
#endif

  sanity_check_edge(edges);
  sanity_check_ccwedge(nedges, edges);

  int nelem;
  elem* elems = NULL;

  build_elem_table(npoints, p, nedges, edges, &nelem, &elems);
  cout << "nelem=" << nelem << endl;

  delete [] elems;

  delete [] edges;
}

void generate_dataset(int n,point* p){
  //make a set of points perturbed from a uniform grid
  srand(0);
  for (int i=0;i<n;i++){
    for(int j=0;j<n;j++){
      p[i+j*n].x=double(i)+double(rand())/RAND_MAX*n*1.e-3;
      p[i+j*n].y=double(j)+double(rand())/RAND_MAX*n*1.e-3;
    }
  }
#if defined(WRITE_FILES)
  {
    const long npoints=n*n;
    ofstream file("points_res");
    file << npoints << endl;
    for(int i=0;i<npoints;++i){
      p[i].write(file);
    }
  }
#endif
}

void test_triangulate_random(int n){
  const long npoints=n*n;
  //set up the point array
  point *p = new point[npoints];
  generate_dataset(n,p);

  test_sort_triangulate(npoints,p);

  delete [] p;
}

void test_triangulate_from_file(){
  long npoints;
  ifstream file("points");
  file >> npoints;
  point *p = new point[npoints];
  for(int i=0;i<npoints;++i){
    file >> p[i].x;
    file >> p[i].y;
  }

  test_sort_triangulate(npoints,p);

  delete [] p;
}

#if defined(USE_MAIN)
int main(void){
# if 1
#   if 0
  int n=3;
  cout << "n= " << n << endl;
  test_triangulate_random(n);

#   else
  for(int n=2; n!=100; n++){
    cout << "n= " << n << endl;
    test_triangulate_random(n);
  }
#   endif
# else
  test_triangulate_from_file();
# endif
}
#endif
<|endoftext|>


<commit_before>/***************************************************************************
 *   Copyright (c) 2011 Werner Mayer <wmayer[at]users.sourceforge.net>     *
 *                                                                         *
 *   This file is part of the FreeCAD CAx development system.              *
 *                                                                         *
 *   This library is free software; you can redistribute it and/or         *
 *   modify it under the terms of the GNU Library General Public           *
 *   License as published by the Free Software Foundation; either          *
 *   version 2 of the License, or (at your option) any later version.      *
 *                                                                         *
 *   This library  is distributed in the hope that it will be useful,      *
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
 *   GNU Library General Public License for more details.                  *
 *                                                                         *
 *   You should have received a copy of the GNU Library General Public     *
 *   License along with this library; see the file COPYING.LIB. If not,    *
 *   write to the Free Software Foundation, Inc., 59 Temple Place,         *
 *   Suite 330, Boston, MA  02111-1307, USA                                *
 *                                                                         *
 ***************************************************************************/

#include "PreCompiled.h"
#ifndef _PreComp_
# include <cfloat>
# include "InventorAll.h"
# include <QAction>
# include <QActionGroup>
# include <QApplication>
# include <QByteArray>
# include <QCursor>
# include <QList>
# include <QMenu>
# include <QMetaObject>
# include <QRegExp>
#endif

#include <Inventor/sensors/SoTimerSensor.h>

#include <App/Application.h>
#include "NavigationStyle.h"
#include "View3DInventorViewer.h"
#include "Application.h"
#include "MenuManager.h"
#include "MouseSelection.h"

using namespace Gui;

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

/* TRANSLATOR Gui::BlenderNavigationStyle */

TYPESYSTEM_SOURCE(Gui::BlenderNavigationStyle, Gui::UserNavigationStyle);

BlenderNavigationStyle::BlenderNavigationStyle() : lockButton1(false)
{
}

BlenderNavigationStyle::~BlenderNavigationStyle()
{
}

const char* BlenderNavigationStyle::mouseButtons(ViewerMode mode)
{
    switch (mode) {
    case NavigationStyle::SELECTION:
        return QT_TR_NOOP("Press left mouse button");
    case NavigationStyle::PANNING:
        return QT_TR_NOOP("Press SHIFT and middle mouse button");
    case NavigationStyle::DRAGGING:
        return QT_TR_NOOP("Press middle mouse button");
    case NavigationStyle::ZOOMING:
        return QT_TR_NOOP("Scroll middle mouse button");
    default:
        return "No description";
    }
}

SbBool BlenderNavigationStyle::processSoEvent(const SoEvent * const ev)
{
    // Events when in "ready-to-seek" mode are ignored, except those
    // which influence the seek mode itself -- these are handled further
    // up the inheritance hierarchy.
    if (this->isSeekMode()) { return inherited::processSoEvent(ev); }
    // Switch off viewing mode (Bug #0000911)
    if (!this->isSeekMode() && !this->isAnimating() && this->isViewing())
        this->setViewing(false); // by default disable viewing mode to render the scene

    const SoType type(ev->getTypeId());

    const SbViewportRegion & vp = viewer->getSoRenderManager()->getViewportRegion();
    const SbVec2s size(vp.getViewportSizePixels());
    const SbVec2f prevnormalized = this->lastmouseposition;
    const SbVec2s pos(ev->getPosition());
    const SbVec2f posn((float) pos[0] / (float) std::max((int)(size[0] - 1), 1),
                       (float) pos[1] / (float) std::max((int)(size[1] - 1), 1));

    this->lastmouseposition = posn;

    // Set to true if any event processing happened. Note that it is not
    // necessary to restrict ourselves to only do one "action" for an
    // event, we only need this flag to see if any processing happened
    // at all.
    SbBool processed = false;

    const ViewerMode curmode = this->currentmode;
    ViewerMode newmode = curmode;

    // Mismatches in state of the modifier keys happens if the user
    // presses or releases them outside the viewer window.
    if (this->ctrldown != ev->wasCtrlDown()) {
        this->ctrldown = ev->wasCtrlDown();
    }
    if (this->shiftdown != ev->wasShiftDown()) {
        this->shiftdown = ev->wasShiftDown();
    }
    if (this->altdown != ev->wasAltDown()) {
        this->altdown = ev->wasAltDown();
    }

    // give the nodes in the foreground root the chance to handle events (e.g color bar)
    if (!processed && !viewer->isEditing()) {
        processed = handleEventInForeground(ev);
        if (processed)
            return true;
    }

    // Keyboard handling
    if (type.isDerivedFrom(SoKeyboardEvent::getClassTypeId())) {
        const SoKeyboardEvent * const event = (const SoKeyboardEvent *) ev;
        const SbBool press = event->getState() == SoButtonEvent::DOWN ? true : false;
        switch (event->getKey()) {
        case SoKeyboardEvent::LEFT_CONTROL:
        case SoKeyboardEvent::RIGHT_CONTROL:
            this->ctrldown = press;
            break;
        case SoKeyboardEvent::LEFT_SHIFT:
        case SoKeyboardEvent::RIGHT_SHIFT:
            this->shiftdown = press;
            break;
        case SoKeyboardEvent::LEFT_ALT:
        case SoKeyboardEvent::RIGHT_ALT:
            this->altdown = press;
            break;
        case SoKeyboardEvent::H:
            processed = true;
            viewer->saveHomePosition();
            break;
        case SoKeyboardEvent::S:
        case SoKeyboardEvent::HOME:
        case SoKeyboardEvent::LEFT_ARROW:
        case SoKeyboardEvent::UP_ARROW:
        case SoKeyboardEvent::RIGHT_ARROW:
        case SoKeyboardEvent::DOWN_ARROW:
            if (!this->isViewing())
                this->setViewing(true);
            break;
        default:
            break;
        }
    }

    // Mouse Button / Spaceball Button handling
    if (type.isDerivedFrom(SoMouseButtonEvent::getClassTypeId())) {
        const SoMouseButtonEvent * const event = (const SoMouseButtonEvent *) ev;
        const int button = event->getButton();
        const SbBool press = event->getState() == SoButtonEvent::DOWN ? true : false;

        //SoDebugError::postInfo("processSoEvent", "button = %d", button);
        switch (button) {
        case SoMouseButtonEvent::BUTTON1:
            this->lockrecenter = true;
            this->button1down = press;
            if (press && (this->currentmode == NavigationStyle::SEEK_WAIT_MODE)) {
                newmode = NavigationStyle::SEEK_MODE;
                this->seekToPoint(pos); // implicitly calls interactiveCountInc()
                processed = true;
            }
            //else if (press && (this->currentmode == NavigationStyle::IDLE)) {
            //    this->setViewing(true);
            //    processed = true;
            //}
            else if (press && (this->currentmode == NavigationStyle::PANNING ||
                               this->currentmode == NavigationStyle::ZOOMING)) {
                newmode = NavigationStyle::DRAGGING;
                saveCursorPosition(ev);
                this->centerTime = ev->getTime();
                processed = true;
            }
            else if (viewer->isEditing() && (this->currentmode == NavigationStyle::SPINNING)) {
                processed = true;
            }
            // issue #0002433: avoid to swallow the UP event if down the
            // scene graph somewhere a dialog gets opened
            else if (press) {
                SbTime tmp = (ev->getTime() - mouseDownConsumedEvent.getTime());
                float dci = (float)QApplication::doubleClickInterval()/1000.0f;
                // a double-click?
                if (tmp.getValue() < dci) {
                    mouseDownConsumedEvent = *event;
                    mouseDownConsumedEvent.setTime(ev->getTime());
                    processed = true;
                }
                else {
                    mouseDownConsumedEvent.setTime(ev->getTime());
                    // 'ANY' is used to mark that we don't know yet if it will
                    // be a double-click event.
                    mouseDownConsumedEvent.setButton(SoMouseButtonEvent::ANY);
                }
            }
            else if (!press) {
                if (mouseDownConsumedEvent.getButton() == SoMouseButtonEvent::BUTTON1) {
                    // now handle the postponed event
                    inherited::processSoEvent(&mouseDownConsumedEvent);
                    mouseDownConsumedEvent.setButton(SoMouseButtonEvent::ANY);
                }
            }
            break;
        case SoMouseButtonEvent::BUTTON2:
            // If we are in edit mode then simply ignore the RMB events
            // to pass the event to the base class.
            this->lockrecenter = true;
            if (!viewer->isEditing()) {
                // If we are in zoom or pan mode ignore RMB events otherwise
                // the canvas doesn't get any release events
                if (this->currentmode != NavigationStyle::ZOOMING &&
                    this->currentmode != NavigationStyle::PANNING &&
                    this->currentmode != NavigationStyle::DRAGGING) {
                    if (this->isPopupMenuEnabled()) {
                        if (!press) { // release right mouse button
                            this->openPopupMenu(event->getPosition());
                        }
                    }
                }
            }
            // Alternative way of rotating & zooming
            if (press && (this->currentmode == NavigationStyle::PANNING ||
                          this->currentmode == NavigationStyle::ZOOMING)) {
                newmode = NavigationStyle::DRAGGING;
                saveCursorPosition(ev);
                this->centerTime = ev->getTime();
                processed = true;
            }
            this->button2down = press;
            break;
        case SoMouseButtonEvent::BUTTON3:
            if (press) {
                this->centerTime = ev->getTime();
                float ratio = vp.getViewportAspectRatio();
                SbViewVolume vv = viewer->getSoRenderManager()->getCamera()->getViewVolume(ratio);
                this->panningplane = vv.getPlane(viewer->getSoRenderManager()->getCamera()->focalDistance.getValue());
                this->lockrecenter = false;
            }
            else {
                SbTime tmp = (ev->getTime() - this->centerTime);
                float dci = (float)QApplication::doubleClickInterval()/1000.0f;
                // is it just a middle click?
                if (tmp.getValue() < dci && !this->lockrecenter) {
                    if (!this->lookAtPoint(pos)) {
                        panToCenter(panningplane, posn);
                        this->interactiveCountDec();
                    }
                    processed = true;
                }
            }
            this->button3down = press;
            break;
        case SoMouseButtonEvent::BUTTON4:
            doZoom(viewer->getSoRenderManager()->getCamera(), true, posn);
            processed = true;
            break;
        case SoMouseButtonEvent::BUTTON5:
            doZoom(viewer->getSoRenderManager()->getCamera(), false, posn);
            processed = true;
            break;
        default:
            break;
        }
    }

    // Mouse Movement handling
    if (type.isDerivedFrom(SoLocation2Event::getClassTypeId())) {
        this->lockrecenter = true;
        const SoLocation2Event * const event = (const SoLocation2Event *) ev;
        if (this->currentmode == NavigationStyle::ZOOMING) {
            this->zoomByCursor(posn, prevnormalized);
            processed = true;
        }
        else if (this->currentmode == NavigationStyle::PANNING) {
            float ratio = vp.getViewportAspectRatio();
            panCamera(viewer->getSoRenderManager()->getCamera(), ratio, this->panningplane, posn, prevnormalized);
            processed = true;
        }
        else if (this->currentmode == NavigationStyle::DRAGGING) {
            this->addToLog(event->getPosition(), event->getTime());
            this->spin(posn);
            moveCursorPosition();
            processed = true;
        }
    }

    // Spaceball & Joystick handling
    if (type.isDerivedFrom(SoMotion3Event::getClassTypeId())) {
        const SoMotion3Event * const event = static_cast<const SoMotion3Event * const>(ev);
        if (event)
            this->processMotionEvent(event);
        processed = true;
    }

    enum {
        BUTTON1DOWN = 1 << 0,
        BUTTON3DOWN = 1 << 1,
        CTRLDOWN =    1 << 2,
        SHIFTDOWN =   1 << 3,
        BUTTON2DOWN = 1 << 4
    };
    unsigned int combo =
        (this->button1down ? BUTTON1DOWN : 0) |
        (this->button2down ? BUTTON2DOWN : 0) |
        (this->button3down ? BUTTON3DOWN : 0) |
        (this->ctrldown ? CTRLDOWN : 0) |
        (this->shiftdown ? SHIFTDOWN : 0);

    switch (combo) {
    case 0:
        if (curmode == NavigationStyle::SPINNING) { break; }
        newmode = NavigationStyle::IDLE;
        // The left mouse button has been released right now but
        // we want to avoid that the event is processed elsewhere
        if (this->lockButton1) {
            this->lockButton1 = false;
            processed = true;
        }

        //if (curmode == NavigationStyle::DRAGGING) {
        //    if (doSpin())
        //        newmode = NavigationStyle::SPINNING;
        //}
        break;
    case BUTTON1DOWN:
    case CTRLDOWN|BUTTON1DOWN:
        // make sure not to change the selection when stopping spinning
        if (curmode == NavigationStyle::SPINNING || this->lockButton1)
            newmode = NavigationStyle::IDLE;
        else
            newmode = NavigationStyle::SELECTION;
        break;
    case BUTTON1DOWN|BUTTON2DOWN:
        newmode = NavigationStyle::PANNING;
        break;
    case SHIFTDOWN|BUTTON3DOWN:
        newmode = NavigationStyle::PANNING;
        break;
    case BUTTON3DOWN:
        if (newmode != NavigationStyle::DRAGGING) {
            saveCursorPosition(ev);
        }
        newmode = NavigationStyle::DRAGGING;
        break;
    //case BUTTON1DOWN|BUTTON2DOWN|BUTTON3DOWN:
    //    newmode = NavigationStyle::ZOOMING;
    //    break;
    case CTRLDOWN|SHIFTDOWN|BUTTON2DOWN:
    case CTRLDOWN|BUTTON3DOWN:
        newmode = NavigationStyle::ZOOMING;
        break;

    default:
        break;
    }

    if (newmode != curmode) {
        this->setViewingMode(newmode);
    }

    // If for dragging the buttons 1 and 3 are pressed
    // but then button 3 is released we shouldn't switch
    // into selection mode.
    if (this->button1down && this->button3down)
        this->lockButton1 = true;

    // If not handled in this class, pass on upwards in the inheritance
    // hierarchy.
    if (/*(curmode == NavigationStyle::SELECTION || viewer->isEditing()) && */!processed)
        processed = inherited::processSoEvent(ev);
    else
        return true;

    return processed;
}
<commit_msg>Fix Blender Navigation<commit_after>/***************************************************************************
 *   Copyright (c) 2011 Werner Mayer <wmayer[at]users.sourceforge.net>     *
 *                                                                         *
 *   This file is part of the FreeCAD CAx development system.              *
 *                                                                         *
 *   This library is free software; you can redistribute it and/or         *
 *   modify it under the terms of the GNU Library General Public           *
 *   License as published by the Free Software Foundation; either          *
 *   version 2 of the License, or (at your option) any later version.      *
 *                                                                         *
 *   This library  is distributed in the hope that it will be useful,      *
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
 *   GNU Library General Public License for more details.                  *
 *                                                                         *
 *   You should have received a copy of the GNU Library General Public     *
 *   License along with this library; see the file COPYING.LIB. If not,    *
 *   write to the Free Software Foundation, Inc., 59 Temple Place,         *
 *   Suite 330, Boston, MA  02111-1307, USA                                *
 *                                                                         *
 ***************************************************************************/

#include "PreCompiled.h"
#ifndef _PreComp_
# include <cfloat>
# include "InventorAll.h"
# include <QAction>
# include <QActionGroup>
# include <QApplication>
# include <QByteArray>
# include <QCursor>
# include <QList>
# include <QMenu>
# include <QMetaObject>
# include <QRegExp>
#endif

#include <Inventor/sensors/SoTimerSensor.h>

#include <App/Application.h>
#include "NavigationStyle.h"
#include "View3DInventorViewer.h"
#include "Application.h"
#include "MenuManager.h"
#include "MouseSelection.h"

using namespace Gui;

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

/* TRANSLATOR Gui::BlenderNavigationStyle */

TYPESYSTEM_SOURCE(Gui::BlenderNavigationStyle, Gui::UserNavigationStyle);

BlenderNavigationStyle::BlenderNavigationStyle() : lockButton1(false)
{
}

BlenderNavigationStyle::~BlenderNavigationStyle()
{
}

const char* BlenderNavigationStyle::mouseButtons(ViewerMode mode)
{
    switch (mode) {
    case NavigationStyle::SELECTION:
        return QT_TR_NOOP("Press left mouse button");
    case NavigationStyle::PANNING:
        return QT_TR_NOOP("Press SHIFT and middle mouse button");
    case NavigationStyle::DRAGGING:
        return QT_TR_NOOP("Press middle mouse button");
    case NavigationStyle::ZOOMING:
        return QT_TR_NOOP("Scroll middle mouse button");
    default:
        return "No description";
    }
}

SbBool BlenderNavigationStyle::processSoEvent(const SoEvent * const ev)
{
    // Events when in "ready-to-seek" mode are ignored, except those
    // which influence the seek mode itself -- these are handled further
    // up the inheritance hierarchy.
    if (this->isSeekMode()) { return inherited::processSoEvent(ev); }
    // Switch off viewing mode (Bug #0000911)
    if (!this->isSeekMode() && !this->isAnimating() && this->isViewing())
        this->setViewing(false); // by default disable viewing mode to render the scene

    const SoType type(ev->getTypeId());

    const SbViewportRegion & vp = viewer->getSoRenderManager()->getViewportRegion();
    const SbVec2s size(vp.getViewportSizePixels());
    const SbVec2f prevnormalized = this->lastmouseposition;
    const SbVec2s pos(ev->getPosition());
    const SbVec2f posn((float) pos[0] / (float) std::max((int)(size[0] - 1), 1),
                       (float) pos[1] / (float) std::max((int)(size[1] - 1), 1));

    this->lastmouseposition = posn;

    // Set to true if any event processing happened. Note that it is not
    // necessary to restrict ourselves to only do one "action" for an
    // event, we only need this flag to see if any processing happened
    // at all.
    SbBool processed = false;

    const ViewerMode curmode = this->currentmode;
    ViewerMode newmode = curmode;

    // Mismatches in state of the modifier keys happens if the user
    // presses or releases them outside the viewer window.
    if (this->ctrldown != ev->wasCtrlDown()) {
        this->ctrldown = ev->wasCtrlDown();
    }
    if (this->shiftdown != ev->wasShiftDown()) {
        this->shiftdown = ev->wasShiftDown();
    }
    if (this->altdown != ev->wasAltDown()) {
        this->altdown = ev->wasAltDown();
    }

    // give the nodes in the foreground root the chance to handle events (e.g color bar)
    if (!processed && !viewer->isEditing()) {
        processed = handleEventInForeground(ev);
        if (processed)
            return true;
    }

    // Keyboard handling
    if (type.isDerivedFrom(SoKeyboardEvent::getClassTypeId())) {
        const SoKeyboardEvent * const event = (const SoKeyboardEvent *) ev;
        const SbBool press = event->getState() == SoButtonEvent::DOWN ? true : false;
        switch (event->getKey()) {
        case SoKeyboardEvent::LEFT_CONTROL:
        case SoKeyboardEvent::RIGHT_CONTROL:
            this->ctrldown = press;
            break;
        case SoKeyboardEvent::LEFT_SHIFT:
        case SoKeyboardEvent::RIGHT_SHIFT:
            this->shiftdown = press;
            break;
        case SoKeyboardEvent::LEFT_ALT:
        case SoKeyboardEvent::RIGHT_ALT:
            this->altdown = press;
            break;
        case SoKeyboardEvent::H:
            processed = true;
            viewer->saveHomePosition();
            break;
        case SoKeyboardEvent::S:
        case SoKeyboardEvent::HOME:
        case SoKeyboardEvent::LEFT_ARROW:
        case SoKeyboardEvent::UP_ARROW:
        case SoKeyboardEvent::RIGHT_ARROW:
        case SoKeyboardEvent::DOWN_ARROW:
            if (!this->isViewing())
                this->setViewing(true);
            break;
        default:
            break;
        }
    }

    // Mouse Button / Spaceball Button handling
    if (type.isDerivedFrom(SoMouseButtonEvent::getClassTypeId())) {
        const SoMouseButtonEvent * const event = (const SoMouseButtonEvent *) ev;
        const int button = event->getButton();
        const SbBool press = event->getState() == SoButtonEvent::DOWN ? true : false;

        //SoDebugError::postInfo("processSoEvent", "button = %d", button);
        switch (button) {
        case SoMouseButtonEvent::BUTTON1:
            this->lockrecenter = true;
            this->button1down = press;
            if (press && (this->currentmode == NavigationStyle::SEEK_WAIT_MODE)) {
                newmode = NavigationStyle::SEEK_MODE;
                this->seekToPoint(pos); // implicitly calls interactiveCountInc()
                processed = true;
            }
            //else if (press && (this->currentmode == NavigationStyle::IDLE)) {
            //    this->setViewing(true);
            //    processed = true;
            //}
            else if (press && (this->currentmode == NavigationStyle::PANNING ||
                               this->currentmode == NavigationStyle::ZOOMING)) {
                newmode = NavigationStyle::DRAGGING;
                saveCursorPosition(ev);
                this->centerTime = ev->getTime();
                processed = true;
            }
            else if (viewer->isEditing() && (this->currentmode == NavigationStyle::SPINNING)) {
                processed = true;
            }
            // issue #0002433: avoid to swallow the UP event if down the
            // scene graph somewhere a dialog gets opened
            else if (press) {
                SbTime tmp = (ev->getTime() - mouseDownConsumedEvent.getTime());
                float dci = (float)QApplication::doubleClickInterval()/1000.0f;
                // a double-click?
                if (tmp.getValue() < dci) {
                    mouseDownConsumedEvent = *event;
                    mouseDownConsumedEvent.setTime(ev->getTime());
                    processed = true;
                }
                else {
                    mouseDownConsumedEvent.setTime(ev->getTime());
                    // 'ANY' is used to mark that we don't know yet if it will
                    // be a double-click event.
                    mouseDownConsumedEvent.setButton(SoMouseButtonEvent::ANY);
                }
            }
            else if (!press) {
                if (mouseDownConsumedEvent.getButton() == SoMouseButtonEvent::BUTTON1) {
                    // now handle the postponed event
                    inherited::processSoEvent(&mouseDownConsumedEvent);
                    mouseDownConsumedEvent.setButton(SoMouseButtonEvent::ANY);
                }
            }
            break;
        case SoMouseButtonEvent::BUTTON2:
            // If we are in edit mode then simply ignore the RMB events
            // to pass the event to the base class.
            this->lockrecenter = true;
            if (!viewer->isEditing()) {
                // If we are in zoom or pan mode ignore RMB events otherwise
                // the canvas doesn't get any release events
                if (this->currentmode != NavigationStyle::ZOOMING &&
                    this->currentmode != NavigationStyle::PANNING &&
                    this->currentmode != NavigationStyle::DRAGGING) {
                    if (this->isPopupMenuEnabled()) {
                        if (!press) { // release right mouse button
                            this->openPopupMenu(event->getPosition());
                        }
                    }
                }
            }
            // Alternative way of rotating & zooming
            if (press && (this->currentmode == NavigationStyle::PANNING ||
                          this->currentmode == NavigationStyle::ZOOMING)) {
                newmode = NavigationStyle::DRAGGING;
                saveCursorPosition(ev);
                this->centerTime = ev->getTime();
                processed = true;
            }
            this->button2down = press;
            break;
        case SoMouseButtonEvent::BUTTON3:
            if (press) {
                this->centerTime = ev->getTime();
                float ratio = vp.getViewportAspectRatio();
                SbViewVolume vv = viewer->getSoRenderManager()->getCamera()->getViewVolume(ratio);
                this->panningplane = vv.getPlane(viewer->getSoRenderManager()->getCamera()->focalDistance.getValue());
                this->lockrecenter = false;
            }
            else {
                SbTime tmp = (ev->getTime() - this->centerTime);
                float dci = (float)QApplication::doubleClickInterval()/1000.0f;
                // is it just a middle click?
                if (tmp.getValue() < dci && !this->lockrecenter) {
                    if (!this->lookAtPoint(pos)) {
                        panToCenter(panningplane, posn);
                        this->interactiveCountDec();
                    }
                    processed = true;
                }
            }
            this->button3down = press;
            break;
        case SoMouseButtonEvent::BUTTON4:
            doZoom(viewer->getSoRenderManager()->getCamera(), true, posn);
            processed = true;
            break;
        case SoMouseButtonEvent::BUTTON5:
            doZoom(viewer->getSoRenderManager()->getCamera(), false, posn);
            processed = true;
            break;
        default:
            break;
        }
    }

    // Mouse Movement handling
    if (type.isDerivedFrom(SoLocation2Event::getClassTypeId())) {
        this->lockrecenter = true;
        const SoLocation2Event * const event = (const SoLocation2Event *) ev;
        if (this->currentmode == NavigationStyle::ZOOMING) {
            this->zoomByCursor(posn, prevnormalized);
            newmode = NavigationStyle::SELECTION;
            processed = true;
        }
        else if (this->currentmode == NavigationStyle::PANNING) {
            float ratio = vp.getViewportAspectRatio();
            panCamera(viewer->getSoRenderManager()->getCamera(), ratio, this->panningplane, posn, prevnormalized);
            newmode = NavigationStyle::SELECTION;
            processed = true;
        }
        else if (this->currentmode == NavigationStyle::DRAGGING) {
            this->addToLog(event->getPosition(), event->getTime());
            this->spin(posn);
            moveCursorPosition();
            processed = true;
        }
    }

    // Spaceball & Joystick handling
    if (type.isDerivedFrom(SoMotion3Event::getClassTypeId())) {
        const SoMotion3Event * const event = static_cast<const SoMotion3Event * const>(ev);
        if (event)
            this->processMotionEvent(event);
        processed = true;
    }

    enum {
        BUTTON1DOWN = 1 << 0,
        BUTTON3DOWN = 1 << 1,
        CTRLDOWN =    1 << 2,
        SHIFTDOWN =   1 << 3,
        BUTTON2DOWN = 1 << 4
    };
    unsigned int combo =
        (this->button1down ? BUTTON1DOWN : 0) |
        (this->button2down ? BUTTON2DOWN : 0) |
        (this->button3down ? BUTTON3DOWN : 0) |
        (this->ctrldown ? CTRLDOWN : 0) |
        (this->shiftdown ? SHIFTDOWN : 0);

    switch (combo) {
    case 0:
        if (curmode == NavigationStyle::SPINNING) { break; }
        newmode = NavigationStyle::IDLE;
        // The left mouse button has been released right now but
        // we want to avoid that the event is processed elsewhere
        if (this->lockButton1) {
            this->lockButton1 = false;
            processed = true;
        }

        //if (curmode == NavigationStyle::DRAGGING) {
        //    if (doSpin())
        //        newmode = NavigationStyle::SPINNING;
        //}
        break;
    case BUTTON1DOWN:
    case CTRLDOWN|BUTTON1DOWN:
        // make sure not to change the selection when stopping spinning
        if (curmode == NavigationStyle::SPINNING || this->lockButton1)
            newmode = NavigationStyle::IDLE;
        else
            newmode = NavigationStyle::SELECTION;
        break;
    case BUTTON1DOWN|BUTTON2DOWN:
        newmode = NavigationStyle::PANNING;
        break;
    case SHIFTDOWN|BUTTON3DOWN:
        newmode = NavigationStyle::PANNING;
        break;
    case BUTTON3DOWN:
        if (newmode != NavigationStyle::DRAGGING) {
            saveCursorPosition(ev);
        }
        newmode = NavigationStyle::DRAGGING;
        break;
    //case BUTTON1DOWN|BUTTON2DOWN|BUTTON3DOWN:
    //    newmode = NavigationStyle::ZOOMING;
    //    break;
    case CTRLDOWN|SHIFTDOWN|BUTTON2DOWN:
    case CTRLDOWN|BUTTON3DOWN:
        newmode = NavigationStyle::ZOOMING;
        break;

    default:
        break;
    }

    if (newmode != curmode) {
        this->setViewingMode(newmode);
    }

    // If for dragging the buttons 1 and 3 are pressed
    // but then button 3 is released we shouldn't switch
    // into selection mode.
    if (this->button1down && this->button3down)
        this->lockButton1 = true;

    // If not handled in this class, pass on upwards in the inheritance
    // hierarchy.
    if (/*(curmode == NavigationStyle::SELECTION || viewer->isEditing()) && */!processed)
        processed = inherited::processSoEvent(ev);
    else
        return true;

    return processed;
}
<|endoftext|>