<commit_before>/*
 * Copyright (C) 2003-2005 Tommi Maekitalo
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * As a special exception, you may use this file as part of a free
 * software library without restriction. Specifically, if other files
 * instantiate templates or use macros or inline functions from this
 * file, or you compile this file and link it with other files to
 * produce an executable, this file does not by itself cause the
 * resulting executable to be covered by the GNU General Public
 * License. This exception does not however invalidate any other
 * reasons why the executable file might be covered by the GNU Library
 * General Public License.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
 */

#include <tnt/httprequest.h>
#include <tnt/httpparser.h>
#include <tnt/httperror.h>
#include <tnt/util.h>
#include <sstream>
#include <cxxtools/log.h>
#include <cxxtools/mutex.h>
#include <cxxtools/base64stream.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <tnt/sessionscope.h>
#include <tnt/socketif.h>
#include <pthread.h>
#include "config.h"
#include <tnt/stringlessignorecase.h>
#include <cstring>

namespace tnt
{
  log_define("tntnet.httprequest")

  ////////////////////////////////////////////////////////////////////////
  // HttpRequest
  //
  cxxtools::atomic_t HttpRequest::serial_ = 0;

  HttpRequest::HttpRequest(Tntnet& application_, const SocketIf* socketIf_)
    : socketIf(socketIf_),
      locale_init(false),
      encodingRead(false),
      requestScope(0),
      applicationScope(0),
      sessionScope(0),
      secureSessionScope(0),
      threadContext(0),
      applicationScopeLocked(false),
      sessionScopeLocked(false),
      secureSessionScopeLocked(false),
      application(application_)
  {
  }

  HttpRequest::HttpRequest(Tntnet& application_, const std::string& url_, const SocketIf* socketIf_)
    : socketIf(socketIf_),
      locale_init(false),
      requestScope(0),
      applicationScope(0),
      sessionScope(0),
      secureSessionScope(0),
      threadContext(0),
      applicationScopeLocked(false),
      sessionScopeLocked(false),
      secureSessionScopeLocked(false),
      application(application_)
  {
    std::istringstream s("GET " + url_ + " HTTP/1.1\r\n\r\n");
    parse(s);
  }

  HttpRequest::HttpRequest(const HttpRequest& r)
    : methodLen(0),
      pathinfo(r.pathinfo),
      args(r.args),
      getparam(r.getparam),
      postparam(r.postparam),
      qparam(r.qparam),
      socketIf(r.socketIf),
      ct(r.ct),
      mp(r.mp),
      serial(r.serial),
      locale_init(r.locale_init),
      locale(r.locale),
      requestScope(r.requestScope),
      applicationScope(r.applicationScope),
      sessionScope(r.sessionScope),
      secureSessionScope(r.secureSessionScope),
      threadContext(r.threadContext),
      applicationScopeLocked(false),
      sessionScopeLocked(false),
      secureSessionScopeLocked(false),
      application(r.application)
  {
    if (requestScope)
      requestScope->addRef();
    if (applicationScope)
      applicationScope->addRef();
    if (sessionScope)
      sessionScope->addRef();
    if (secureSessionScope)
      secureSessionScope->addRef();
  }

  HttpRequest::~HttpRequest()
  {
    releaseLocks();

    if (requestScope && requestScope->release() == 0)
      delete requestScope;
    if (applicationScope && applicationScope->release() == 0)
      delete applicationScope;
    if (sessionScope && sessionScope->release() == 0)
      delete sessionScope;
    if (secureSessionScope && secureSessionScope->release() == 0)
      delete secureSessionScope;
  }

  HttpRequest& HttpRequest::operator= (const HttpRequest& r)
  {
    pathinfo = r.pathinfo;
    args = r.args;
    getparam = r.getparam;
    postparam = r.postparam;
    qparam = r.qparam;
    ct = r.ct;
    mp = r.mp;
    socketIf = r.socketIf;
    serial = r.serial;
    locale_init = r.locale_init;
    locale = r.locale;
    requestScope = r.requestScope;
    applicationScope = r.applicationScope;
    sessionScope = r.sessionScope;
    secureSessionScope = r.secureSessionScope;
    threadContext = r.threadContext;
    applicationScopeLocked = false;
    sessionScopeLocked = false;
    secureSessionScopeLocked = false;

    if (requestScope)
      requestScope->addRef();
    if (applicationScope)
      applicationScope->addRef();
    if (sessionScope)
      sessionScope->addRef();
    if (secureSessionScope)
      secureSessionScope->addRef();

    return *this;
  }

  void HttpRequest::clear()
  {
    HttpMessage::clear();
    body.clear();
    methodLen = 0;
    method[0] = '\0';
    url.clear();
    queryString.clear();
    contentSize = 0;
    pathinfo.clear();
    args.clear();
    getparam.clear();
    postparam.clear();
    qparam.clear();
    ct = Contenttype();
    mp = Multipart();
    locale_init = false;
    if (requestScope)
    {
      if (requestScope->release() == 0)
        delete requestScope;
      requestScope = 0;
    }
    httpcookies.clear();
    encodingRead = false;
    username.clear();
    password.clear();

    releaseLocks();

    if (applicationScope)
    {
      if (applicationScope->release() == 0)
        delete applicationScope;
      applicationScope = 0;
    }

    if (sessionScope)
    {
      if (sessionScope->release() == 0)
        delete sessionScope;
      sessionScope = 0;
    }

    if (secureSessionScope)
    {
      if (secureSessionScope->release() == 0)
        delete secureSessionScope;
      secureSessionScope = 0;
    }

    threadContext = 0;
  }

  void HttpRequest::setMethod(const char* m)
  {
    if (strlen(m) >= 7)
      throw HttpError(HTTP_BAD_REQUEST, "invalid method");
    std::strcpy(method, m);
  }

  std::string HttpRequest::getArgDef(args_type::size_type n, const std::string& def) const
  {
    std::ostringstream k;
    k << "arg" << n;
    return getArg(k.str());
  }

  std::string HttpRequest::getArg(const std::string& name, const std::string& def) const
  {
    args_type::const_iterator it = args.find(name);
    return it == args.end() ? def : it->second;
  }

  void HttpRequest::parse(std::istream& in)
  {
    Parser p(*this);
    p.parse(in);
    if (!p.failed())
      doPostParse();
  }

  void HttpRequest::doPostParse()
  {
    if (hasHeader("Expect:"))
      throw HttpError(HTTP_EXPECTATION_FAILED, "expectation failed", "Expect not supported by this server");

    getparam.parse_url(getQueryString());

    if (isMethodPOST())
    {
      std::istringstream in(getHeader(httpheader::contentType));
      in >> ct;

      if (in)
      {
        if (ct.isMultipart())
        {
          mp.set(ct.getBoundary(), getBody());
          for (Multipart::const_iterator it = mp.begin();
               it != mp.end(); ++it)
          {
            // don't copy uploaded files into qparam to prevent unnecessery
            // copies of large chunks
            if (it->getFilename().empty())
            {
              std::string multipartBody(it->getBodyBegin(), it->getBodyEnd());
              postparam.add(it->getName(), multipartBody);
            }
          }
        }
        else if (ct.getType() == "application"
              && ct.getSubtype() == "x-www-form-urlencoded")
        {
          postparam.parse_url(getBody());
        }
      }
    }

    qparam.add(getparam);
    qparam.add(postparam);

    serial = cxxtools::atomicIncrement(serial_);
  }

  namespace
  {
    typedef std::map<std::string, std::locale> locale_map_type;
    static std::locale* stdlocale = 0;
    static locale_map_type locale_map;
    static cxxtools::Mutex locale_monitor;

    const std::locale& getCacheLocale(const std::string& lang)
    {

      if (stdlocale == 0)
      {
        cxxtools::MutexLock lock(locale_monitor);
        if (stdlocale == 0)
        {
          try
          {
            stdlocale = new std::locale("");
          }
          catch (const std::exception& e)
          {
            log_warn("error initializing standard-locale - using locale \"C\"");
          }
        }
      }

      if (lang.empty() || lang == stdlocale->name())
        return *stdlocale;

      try
      {
        cxxtools::MutexLock lock(locale_monitor);
        locale_map_type::const_iterator it = locale_map.find(lang);
        if (it == locale_map.end())
        {
          std::locale loc = std::locale(lang.c_str());
          return locale_map.insert(locale_map_type::value_type(lang, loc)).first->second;
        }
        else
          return it->second;
      }
      catch (const std::exception& e)
      {
        log_warn("unknown locale " << lang << ": " << e.what());
        locale_map.insert(locale_map_type::value_type(lang, *stdlocale));
        return *stdlocale;
      }
    }

    void clearLocaleCache()
    {
      cxxtools::MutexLock lock(locale_monitor);
      locale_map.clear();
      delete stdlocale;
      stdlocale = 0;
    }
  }

  const std::locale& HttpRequest::getLocale() const
  {
    if (!locale_init)
    {
      static const std::string LANG = "LANG";
      lang = qparam[LANG];
      locale = getCacheLocale(qparam[LANG]);
      if (lang.empty())
        lang = locale.name();
      locale_init = true;
    }

    return locale;
  }

  void HttpRequest::setLocale(const std::locale& loc)
  {
    locale_init = true;
    locale = loc;
    lang = loc.name();
  }

  void HttpRequest::setLang(const std::string& lang_)
  {
    lang = lang_;
    locale = getCacheLocale(lang_);
    locale_init = true;
  }

  const Cookies& HttpRequest::getCookies() const
  {
    if (!httpcookies.hasCookies())
    {
      header_type::const_iterator it = header.find(httpheader::cookie);
      if (it != header.end())
        const_cast<HttpRequest*>(this)->httpcookies.set(it->second);
    }

    return httpcookies;
  }

  const Encoding& HttpRequest::getEncoding() const
  {
    if (!encodingRead)
    {
      encoding.parse(getHeader(httpheader::acceptEncoding));
      encodingRead = true;
    }
    return encoding;
  }

  const std::string& HttpRequest::getUsername() const
  {
    if (username.empty() && hasHeader(httpheader::authorization))
    {
      std::istringstream authHeader(getHeader(httpheader::authorization));
      while (authHeader && authHeader.get() != ' ')
        ;
      cxxtools::Base64istream in(authHeader);
      std::getline(in, username, ':');
      std::getline(in, password);
    }

    return username;
  }

  const std::string& HttpRequest::getPassword() const
  {
    getUsername();
    return password;
  }

  bool HttpRequest::verifyPassword(const std::string& password_) const
  {
    getUsername();
    return password == password_;
  }

  bool HttpRequest::keepAlive() const
  {
    // request is keep alive when either a connection header is explicitely set to keep alive
    // or the http version is 1.1
    Messageheader::const_iterator it = header.find(httpheader::connection);

    return it == header.end()
               ? getMinorVersion() >= 1 && getMajorVersion() >= 1
               : tnt::StringCompareIgnoreCase<const char*>(it->second,
                    httpheader::connectionKeepAlive) == 0;
  }

  const Contenttype& HttpRequest::getContentTypePriv() const
  {
    std::istringstream in(getHeader(httpheader::contentType));
    in >> ct;
    return ct;
  }

  void HttpRequest::setApplicationScope(Scope* s)
  {
    if (applicationScope == s)
      return;

    if (applicationScope)
    {
      releaseApplicationScopeLock();
      if (applicationScope->release() == 0)
        delete applicationScope;
    }

    if (s)
      s->addRef();
    applicationScope = s;
  }

  void HttpRequest::setSessionScope(Sessionscope* s)
  {
    if (sessionScope == s)
      return;

    if (sessionScope)
    {
      if (sessionScopeLocked)
      {
        sessionScope->unlock();
        sessionScopeLocked = false;
      }
      if (sessionScope->release() == 0)
        delete sessionScope;
    }

    if (s)
      s->addRef();

    sessionScope = s;
  }

  void HttpRequest::setSecureSessionScope(Sessionscope* s)
  {
    if (secureSessionScope == s)
      return;

    if (secureSessionScope)
    {
      if (secureSessionScopeLocked)
      {
        secureSessionScope->unlock();
        secureSessionScopeLocked = false;
      }
      if (secureSessionScope->release() == 0)
        delete secureSessionScope;
    }

    if (s)
      s->addRef();

    secureSessionScope = s;
  }

  void HttpRequest::clearSession()
  {
    log_info("end session");

    if (sessionScope)
    {
      if (sessionScopeLocked)
      {
        sessionScope->unlock();
        sessionScopeLocked = false;
      }

      if (sessionScope->release() == 0)
        delete sessionScope;
      sessionScope = 0;
    }

    if (secureSessionScope)
    {
      if (secureSessionScopeLocked)
      {
        secureSessionScope->unlock();
        secureSessionScopeLocked = false;
      }

      if (secureSessionScope->release() == 0)
        delete secureSessionScope;
      secureSessionScope = 0;
    }

  }

  void HttpRequest::ensureApplicationScopeLock()
  {
    ensureSessionScopeLock();
    if (applicationScope && !applicationScopeLocked)
    {
      applicationScope->lock();
      applicationScopeLocked = true;
    }
  }

  void HttpRequest::ensureSessionScopeLock()
  {
    if (sessionScope && !sessionScopeLocked)
    {
      sessionScope->lock();
      sessionScopeLocked = true;
    }

    if (secureSessionScope && !secureSessionScopeLocked)
    {
      secureSessionScope->lock();
      secureSessionScopeLocked = true;
    }

  }

  void HttpRequest::releaseApplicationScopeLock()
  {
    releaseSessionScopeLock();

    if (applicationScope && applicationScopeLocked)
    {
      applicationScopeLocked = false;
      applicationScope->unlock();
    }
  }

  void HttpRequest::releaseSessionScopeLock()
  {
    if (secureSessionScope && secureSessionScopeLocked)
    {
      secureSessionScopeLocked = false;
      secureSessionScope->unlock();
    }

    if (sessionScope && sessionScopeLocked)
    {
      sessionScopeLocked = false;
      sessionScope->unlock();
    }
  }

  Scope& HttpRequest::getRequestScope()
  {
    if (requestScope == 0)
      requestScope = new Scope();
    return *requestScope;
  }

  Scope& HttpRequest::getThreadScope()
  {
    if (threadContext == 0)
      throwRuntimeError("threadcontext not set");
    return threadContext->getScope();
  }

  Scope& HttpRequest::getApplicationScope()
  {
    ensureApplicationScopeLock();
    return *applicationScope;
  }

  Sessionscope& HttpRequest::getSessionScope()
  {
    if (!sessionScope)
      sessionScope = new Sessionscope();
    ensureSessionScopeLock();
    return *sessionScope;
  }

  Sessionscope& HttpRequest::getSecureSessionScope()
  {
    if (!secureSessionScope)
      secureSessionScope = new Sessionscope();
    ensureSessionScopeLock();
    return *secureSessionScope;
  }

  bool HttpRequest::hasSessionScope() const
  {
    return sessionScope != 0 && !sessionScope->empty();
  }

  bool HttpRequest::hasSecureSessionScope() const
  {
    return secureSessionScope != 0 && !secureSessionScope->empty();
  }

  void HttpRequest::postRunCleanup()
  {
    tnt::clearLocaleCache();
  }
}

<commit_msg>bugfix: request.getArgDef(number, default) did not use the default value<commit_after>/*
 * Copyright (C) 2003-2005 Tommi Maekitalo
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * As a special exception, you may use this file as part of a free
 * software library without restriction. Specifically, if other files
 * instantiate templates or use macros or inline functions from this
 * file, or you compile this file and link it with other files to
 * produce an executable, this file does not by itself cause the
 * resulting executable to be covered by the GNU General Public
 * License. This exception does not however invalidate any other
 * reasons why the executable file might be covered by the GNU Library
 * General Public License.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
 */

#include <tnt/httprequest.h>
#include <tnt/httpparser.h>
#include <tnt/httperror.h>
#include <tnt/util.h>
#include <sstream>
#include <cxxtools/log.h>
#include <cxxtools/mutex.h>
#include <cxxtools/base64stream.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <tnt/sessionscope.h>
#include <tnt/socketif.h>
#include <pthread.h>
#include "config.h"
#include <tnt/stringlessignorecase.h>
#include <cstring>

namespace tnt
{
  log_define("tntnet.httprequest")

  ////////////////////////////////////////////////////////////////////////
  // HttpRequest
  //
  cxxtools::atomic_t HttpRequest::serial_ = 0;

  HttpRequest::HttpRequest(Tntnet& application_, const SocketIf* socketIf_)
    : socketIf(socketIf_),
      locale_init(false),
      encodingRead(false),
      requestScope(0),
      applicationScope(0),
      sessionScope(0),
      secureSessionScope(0),
      threadContext(0),
      applicationScopeLocked(false),
      sessionScopeLocked(false),
      secureSessionScopeLocked(false),
      application(application_)
  {
  }

  HttpRequest::HttpRequest(Tntnet& application_, const std::string& url_, const SocketIf* socketIf_)
    : socketIf(socketIf_),
      locale_init(false),
      requestScope(0),
      applicationScope(0),
      sessionScope(0),
      secureSessionScope(0),
      threadContext(0),
      applicationScopeLocked(false),
      sessionScopeLocked(false),
      secureSessionScopeLocked(false),
      application(application_)
  {
    std::istringstream s("GET " + url_ + " HTTP/1.1\r\n\r\n");
    parse(s);
  }

  HttpRequest::HttpRequest(const HttpRequest& r)
    : methodLen(0),
      pathinfo(r.pathinfo),
      args(r.args),
      getparam(r.getparam),
      postparam(r.postparam),
      qparam(r.qparam),
      socketIf(r.socketIf),
      ct(r.ct),
      mp(r.mp),
      serial(r.serial),
      locale_init(r.locale_init),
      locale(r.locale),
      requestScope(r.requestScope),
      applicationScope(r.applicationScope),
      sessionScope(r.sessionScope),
      secureSessionScope(r.secureSessionScope),
      threadContext(r.threadContext),
      applicationScopeLocked(false),
      sessionScopeLocked(false),
      secureSessionScopeLocked(false),
      application(r.application)
  {
    if (requestScope)
      requestScope->addRef();
    if (applicationScope)
      applicationScope->addRef();
    if (sessionScope)
      sessionScope->addRef();
    if (secureSessionScope)
      secureSessionScope->addRef();
  }

  HttpRequest::~HttpRequest()
  {
    releaseLocks();

    if (requestScope && requestScope->release() == 0)
      delete requestScope;
    if (applicationScope && applicationScope->release() == 0)
      delete applicationScope;
    if (sessionScope && sessionScope->release() == 0)
      delete sessionScope;
    if (secureSessionScope && secureSessionScope->release() == 0)
      delete secureSessionScope;
  }

  HttpRequest& HttpRequest::operator= (const HttpRequest& r)
  {
    pathinfo = r.pathinfo;
    args = r.args;
    getparam = r.getparam;
    postparam = r.postparam;
    qparam = r.qparam;
    ct = r.ct;
    mp = r.mp;
    socketIf = r.socketIf;
    serial = r.serial;
    locale_init = r.locale_init;
    locale = r.locale;
    requestScope = r.requestScope;
    applicationScope = r.applicationScope;
    sessionScope = r.sessionScope;
    secureSessionScope = r.secureSessionScope;
    threadContext = r.threadContext;
    applicationScopeLocked = false;
    sessionScopeLocked = false;
    secureSessionScopeLocked = false;

    if (requestScope)
      requestScope->addRef();
    if (applicationScope)
      applicationScope->addRef();
    if (sessionScope)
      sessionScope->addRef();
    if (secureSessionScope)
      secureSessionScope->addRef();

    return *this;
  }

  void HttpRequest::clear()
  {
    HttpMessage::clear();
    body.clear();
    methodLen = 0;
    method[0] = '\0';
    url.clear();
    queryString.clear();
    contentSize = 0;
    pathinfo.clear();
    args.clear();
    getparam.clear();
    postparam.clear();
    qparam.clear();
    ct = Contenttype();
    mp = Multipart();
    locale_init = false;
    if (requestScope)
    {
      if (requestScope->release() == 0)
        delete requestScope;
      requestScope = 0;
    }
    httpcookies.clear();
    encodingRead = false;
    username.clear();
    password.clear();

    releaseLocks();

    if (applicationScope)
    {
      if (applicationScope->release() == 0)
        delete applicationScope;
      applicationScope = 0;
    }

    if (sessionScope)
    {
      if (sessionScope->release() == 0)
        delete sessionScope;
      sessionScope = 0;
    }

    if (secureSessionScope)
    {
      if (secureSessionScope->release() == 0)
        delete secureSessionScope;
      secureSessionScope = 0;
    }

    threadContext = 0;
  }

  void HttpRequest::setMethod(const char* m)
  {
    if (strlen(m) >= 7)
      throw HttpError(HTTP_BAD_REQUEST, "invalid method");
    std::strcpy(method, m);
  }

  std::string HttpRequest::getArgDef(args_type::size_type n, const std::string& def) const
  {
    std::ostringstream k;
    k << "arg" << n;
    return getArg(k.str(), def);
  }

  std::string HttpRequest::getArg(const std::string& name, const std::string& def) const
  {
    args_type::const_iterator it = args.find(name);
    return it == args.end() ? def : it->second;
  }

  void HttpRequest::parse(std::istream& in)
  {
    Parser p(*this);
    p.parse(in);
    if (!p.failed())
      doPostParse();
  }

  void HttpRequest::doPostParse()
  {
    if (hasHeader("Expect:"))
      throw HttpError(HTTP_EXPECTATION_FAILED, "expectation failed", "Expect not supported by this server");

    getparam.parse_url(getQueryString());

    if (isMethodPOST())
    {
      std::istringstream in(getHeader(httpheader::contentType));
      in >> ct;

      if (in)
      {
        if (ct.isMultipart())
        {
          mp.set(ct.getBoundary(), getBody());
          for (Multipart::const_iterator it = mp.begin();
               it != mp.end(); ++it)
          {
            // don't copy uploaded files into qparam to prevent unnecessery
            // copies of large chunks
            if (it->getFilename().empty())
            {
              std::string multipartBody(it->getBodyBegin(), it->getBodyEnd());
              postparam.add(it->getName(), multipartBody);
            }
          }
        }
        else if (ct.getType() == "application"
              && ct.getSubtype() == "x-www-form-urlencoded")
        {
          postparam.parse_url(getBody());
        }
      }
    }

    qparam.add(getparam);
    qparam.add(postparam);

    serial = cxxtools::atomicIncrement(serial_);
  }

  namespace
  {
    typedef std::map<std::string, std::locale> locale_map_type;
    static std::locale* stdlocale = 0;
    static locale_map_type locale_map;
    static cxxtools::Mutex locale_monitor;

    const std::locale& getCacheLocale(const std::string& lang)
    {

      if (stdlocale == 0)
      {
        cxxtools::MutexLock lock(locale_monitor);
        if (stdlocale == 0)
        {
          try
          {
            stdlocale = new std::locale("");
          }
          catch (const std::exception& e)
          {
            log_warn("error initializing standard-locale - using locale \"C\"");
          }
        }
      }

      if (lang.empty() || lang == stdlocale->name())
        return *stdlocale;

      try
      {
        cxxtools::MutexLock lock(locale_monitor);
        locale_map_type::const_iterator it = locale_map.find(lang);
        if (it == locale_map.end())
        {
          std::locale loc = std::locale(lang.c_str());
          return locale_map.insert(locale_map_type::value_type(lang, loc)).first->second;
        }
        else
          return it->second;
      }
      catch (const std::exception& e)
      {
        log_warn("unknown locale " << lang << ": " << e.what());
        locale_map.insert(locale_map_type::value_type(lang, *stdlocale));
        return *stdlocale;
      }
    }

    void clearLocaleCache()
    {
      cxxtools::MutexLock lock(locale_monitor);
      locale_map.clear();
      delete stdlocale;
      stdlocale = 0;
    }
  }

  const std::locale& HttpRequest::getLocale() const
  {
    if (!locale_init)
    {
      static const std::string LANG = "LANG";
      lang = qparam[LANG];
      locale = getCacheLocale(qparam[LANG]);
      if (lang.empty())
        lang = locale.name();
      locale_init = true;
    }

    return locale;
  }

  void HttpRequest::setLocale(const std::locale& loc)
  {
    locale_init = true;
    locale = loc;
    lang = loc.name();
  }

  void HttpRequest::setLang(const std::string& lang_)
  {
    lang = lang_;
    locale = getCacheLocale(lang_);
    locale_init = true;
  }

  const Cookies& HttpRequest::getCookies() const
  {
    if (!httpcookies.hasCookies())
    {
      header_type::const_iterator it = header.find(httpheader::cookie);
      if (it != header.end())
        const_cast<HttpRequest*>(this)->httpcookies.set(it->second);
    }

    return httpcookies;
  }

  const Encoding& HttpRequest::getEncoding() const
  {
    if (!encodingRead)
    {
      encoding.parse(getHeader(httpheader::acceptEncoding));
      encodingRead = true;
    }
    return encoding;
  }

  const std::string& HttpRequest::getUsername() const
  {
    if (username.empty() && hasHeader(httpheader::authorization))
    {
      std::istringstream authHeader(getHeader(httpheader::authorization));
      while (authHeader && authHeader.get() != ' ')
        ;
      cxxtools::Base64istream in(authHeader);
      std::getline(in, username, ':');
      std::getline(in, password);
    }

    return username;
  }

  const std::string& HttpRequest::getPassword() const
  {
    getUsername();
    return password;
  }

  bool HttpRequest::verifyPassword(const std::string& password_) const
  {
    getUsername();
    return password == password_;
  }

  bool HttpRequest::keepAlive() const
  {
    // request is keep alive when either a connection header is explicitely set to keep alive
    // or the http version is 1.1
    Messageheader::const_iterator it = header.find(httpheader::connection);

    return it == header.end()
               ? getMinorVersion() >= 1 && getMajorVersion() >= 1
               : tnt::StringCompareIgnoreCase<const char*>(it->second,
                    httpheader::connectionKeepAlive) == 0;
  }

  const Contenttype& HttpRequest::getContentTypePriv() const
  {
    std::istringstream in(getHeader(httpheader::contentType));
    in >> ct;
    return ct;
  }

  void HttpRequest::setApplicationScope(Scope* s)
  {
    if (applicationScope == s)
      return;

    if (applicationScope)
    {
      releaseApplicationScopeLock();
      if (applicationScope->release() == 0)
        delete applicationScope;
    }

    if (s)
      s->addRef();
    applicationScope = s;
  }

  void HttpRequest::setSessionScope(Sessionscope* s)
  {
    if (sessionScope == s)
      return;

    if (sessionScope)
    {
      if (sessionScopeLocked)
      {
        sessionScope->unlock();
        sessionScopeLocked = false;
      }
      if (sessionScope->release() == 0)
        delete sessionScope;
    }

    if (s)
      s->addRef();

    sessionScope = s;
  }

  void HttpRequest::setSecureSessionScope(Sessionscope* s)
  {
    if (secureSessionScope == s)
      return;

    if (secureSessionScope)
    {
      if (secureSessionScopeLocked)
      {
        secureSessionScope->unlock();
        secureSessionScopeLocked = false;
      }
      if (secureSessionScope->release() == 0)
        delete secureSessionScope;
    }

    if (s)
      s->addRef();

    secureSessionScope = s;
  }

  void HttpRequest::clearSession()
  {
    log_info("end session");

    if (sessionScope)
    {
      if (sessionScopeLocked)
      {
        sessionScope->unlock();
        sessionScopeLocked = false;
      }

      if (sessionScope->release() == 0)
        delete sessionScope;
      sessionScope = 0;
    }

    if (secureSessionScope)
    {
      if (secureSessionScopeLocked)
      {
        secureSessionScope->unlock();
        secureSessionScopeLocked = false;
      }

      if (secureSessionScope->release() == 0)
        delete secureSessionScope;
      secureSessionScope = 0;
    }

  }

  void HttpRequest::ensureApplicationScopeLock()
  {
    ensureSessionScopeLock();
    if (applicationScope && !applicationScopeLocked)
    {
      applicationScope->lock();
      applicationScopeLocked = true;
    }
  }

  void HttpRequest::ensureSessionScopeLock()
  {
    if (sessionScope && !sessionScopeLocked)
    {
      sessionScope->lock();
      sessionScopeLocked = true;
    }

    if (secureSessionScope && !secureSessionScopeLocked)
    {
      secureSessionScope->lock();
      secureSessionScopeLocked = true;
    }

  }

  void HttpRequest::releaseApplicationScopeLock()
  {
    releaseSessionScopeLock();

    if (applicationScope && applicationScopeLocked)
    {
      applicationScopeLocked = false;
      applicationScope->unlock();
    }
  }

  void HttpRequest::releaseSessionScopeLock()
  {
    if (secureSessionScope && secureSessionScopeLocked)
    {
      secureSessionScopeLocked = false;
      secureSessionScope->unlock();
    }

    if (sessionScope && sessionScopeLocked)
    {
      sessionScopeLocked = false;
      sessionScope->unlock();
    }
  }

  Scope& HttpRequest::getRequestScope()
  {
    if (requestScope == 0)
      requestScope = new Scope();
    return *requestScope;
  }

  Scope& HttpRequest::getThreadScope()
  {
    if (threadContext == 0)
      throwRuntimeError("threadcontext not set");
    return threadContext->getScope();
  }

  Scope& HttpRequest::getApplicationScope()
  {
    ensureApplicationScopeLock();
    return *applicationScope;
  }

  Sessionscope& HttpRequest::getSessionScope()
  {
    if (!sessionScope)
      sessionScope = new Sessionscope();
    ensureSessionScopeLock();
    return *sessionScope;
  }

  Sessionscope& HttpRequest::getSecureSessionScope()
  {
    if (!secureSessionScope)
      secureSessionScope = new Sessionscope();
    ensureSessionScopeLock();
    return *secureSessionScope;
  }

  bool HttpRequest::hasSessionScope() const
  {
    return sessionScope != 0 && !sessionScope->empty();
  }

  bool HttpRequest::hasSecureSessionScope() const
  {
    return secureSessionScope != 0 && !secureSessionScope->empty();
  }

  void HttpRequest::postRunCleanup()
  {
    tnt::clearLocaleCache();
  }
}

<|endoftext|>


<commit_before>#include "BasicAIModule.h"
using namespace BWAPI;

void BasicAIModule::onStart()
{
  this->showManagerAssignments=false;
  if (Broodwar->isReplay()) return;
  // Enable some cheat flags
  Broodwar->enableFlag(Flag::UserInput);
  Broodwar->enableFlag(Flag::CompleteMapInformation);
  BWTA::readMap();
  BWTA::analyze();
  this->analyzed=true;
  this->buildManager      = new BuildManager(&this->arbitrator);
  this->techManager       = new TechManager(&this->arbitrator);
  this->upgradeManager    = new UpgradeManager(&this->arbitrator);
  this->buildOrderManager = new BuildOrderManager(this->buildManager,this->techManager,this->upgradeManager);
  this->scoutManager      = new ScoutManager(&this->arbitrator);
  this->workerManager     = new WorkerManager(&this->arbitrator);
  this->baseManager       = new BaseManager();
  this->supplyManager     = new SupplyManager();

  this->supplyManager->setBuildManager(this->buildManager);
  this->supplyManager->setBuildOrderManager(this->buildOrderManager);
  this->techManager->setBuildingPlacer(this->buildManager->getBuildingPlacer());
  this->upgradeManager->setBuildingPlacer(this->buildManager->getBuildingPlacer());
  this->workerManager->setBaseManager(this->baseManager);
  this->baseManager->setBuildOrderManager(this->buildOrderManager);

  BWAPI::Race race = Broodwar->self()->getRace();
  BWAPI::UnitType workerType=*(race.getWorker());
  this->buildOrderManager->build(20,workerType,80);
  //make the basic production facility
  if (race == BWAPI::Races::Zerg)
  {
    //send an overlord out if Zerg
    this->scoutManager->setScoutCount(1);
    this->buildManager->build(BWAPI::UnitTypes::Zerg_Spawning_Pool);
    this->buildManager->build(BWAPI::UnitTypes::Zerg_Zergling);
    this->buildManager->build(BWAPI::UnitTypes::Zerg_Zergling);
    this->buildManager->build(BWAPI::UnitTypes::Zerg_Zergling);
  }
  else if (race == BWAPI::Races::Terran)
  {
    this->buildManager->build(BWAPI::UnitTypes::Terran_Barracks);
    this->buildManager->build(BWAPI::UnitTypes::Terran_Marine);
    this->buildManager->build(BWAPI::UnitTypes::Terran_Marine);
  }
  else if (race == BWAPI::Races::Protoss)
  {
    this->buildManager->build(BWAPI::UnitTypes::Protoss_Gateway);
    this->buildManager->build(BWAPI::UnitTypes::Protoss_Zealot);
  }

}

void BasicAIModule::onFrame()
{
  if (Broodwar->isReplay()) return;
  if (!this->analyzed) return;
  this->buildManager->update();
  this->buildOrderManager->update();
  this->baseManager->update();
  this->workerManager->update();
  this->techManager->update();
  this->upgradeManager->update();
  this->supplyManager->update();
  this->scoutManager->update();
  this->arbitrator.update();
  if (Broodwar->getFrameCount()>24*50)
    scoutManager->setScoutCount(1);

  std::set<Unit*> units=Broodwar->self()->getUnits();
  if (this->showManagerAssignments)
  {
    for(std::set<Unit*>::iterator i=units.begin();i!=units.end();i++)
    {
      if (this->arbitrator.hasBid(*i))
      {
        int x=(*i)->getPosition().x();
        int y=(*i)->getPosition().y();
        std::list< std::pair< Arbitrator::Controller<BWAPI::Unit*,double>*, double> > bids=this->arbitrator.getAllBidders(*i);
        int y_off=0;
        for(std::list< std::pair< Arbitrator::Controller<BWAPI::Unit*,double>*, double> >::iterator j=bids.begin();j!=bids.end();j++)
        {
          Broodwar->drawText(CoordinateType::Map,x,y+y_off,"%s: %d",j->first->getName().c_str(),(int)j->second);
          y_off+=20;
        }
      }
    }
  }
  /*
  for(std::set<Unit*>::iterator i=units.begin();i!=units.end();i++)
  {
    int x=(*i)->getPosition().x();
    int y=(*i)->getPosition().y();
    Broodwar->drawCircle(CoordinateType::Map,x,y,(*i)->getType().airWeapon()->maxRange(),Colors::Blue,false);
    Broodwar->drawCircle(CoordinateType::Map,x,y,(*i)->getType().groundWeapon()->maxRange(),Colors::Green,false);
  }
  */

  //we will iterate through all the base locations, and draw their outlines.
  for(std::set<BWTA::BaseLocation*>::const_iterator i=BWTA::getBaseLocations().begin();i!=BWTA::getBaseLocations().end();i++)
  {
    TilePosition p=(*i)->getTilePosition();
    Position c=(*i)->getPosition();

    //draw outline of center location
    Broodwar->drawBox(CoordinateType::Map,p.x()*32,p.y()*32,p.x()*32+4*32,p.y()*32+3*32,Colors::Blue,false);

    //draw a circle at each mineral patch
    for(std::set<BWAPI::Unit*>::const_iterator j=(*i)->getMinerals().begin();j!=(*i)->getMinerals().end();j++)
    {
      Position q=(*j)->getPosition();
      Broodwar->drawCircle(CoordinateType::Map,q.x(),q.y(),30,Colors::Cyan,false);
    }

    //draw the outlines of vespene geysers
    for(std::set<BWAPI::Unit*>::const_iterator j=(*i)->getGeysers().begin();j!=(*i)->getGeysers().end();j++)
    {
      TilePosition q=(*j)->getTilePosition();
      Broodwar->drawBox(CoordinateType::Map,q.x()*32,q.y()*32,q.x()*32+4*32,q.y()*32+2*32,Colors::Orange,false);
    }

    //if this is an island expansion, draw a yellow circle around the base location
    if ((*i)->isIsland())
    {
      Broodwar->drawCircle(CoordinateType::Map,c.x(),c.y(),80,Colors::Yellow,false);
    }
  }

  //we will iterate through all the regions and draw the polygon outline of it in green.
  for(std::set<BWTA::Region*>::const_iterator r=BWTA::getRegions().begin();r!=BWTA::getRegions().end();r++)
  {
    BWTA::Polygon p=(*r)->getPolygon();
    for(int j=0;j<(int)p.size();j++)
    {
      Position point1=p[j];
      Position point2=p[(j+1) % p.size()];
      Broodwar->drawLine(CoordinateType::Map,point1.x(),point1.y(),point2.x(),point2.y(),Colors::Green);
    }
  }

  //we will visualize the chokepoints with red lines
  for(std::set<BWTA::Region*>::const_iterator r=BWTA::getRegions().begin();r!=BWTA::getRegions().end();r++)
  {
    for(std::set<BWTA::Chokepoint*>::const_iterator c=(*r)->getChokepoints().begin();c!=(*r)->getChokepoints().end();c++)
    {
      Position point1=(*c)->getSides().first;
      Position point2=(*c)->getSides().second;
      Broodwar->drawLine(CoordinateType::Map,point1.x(),point1.y(),point2.x(),point2.y(),Colors::Red);
    }
  }
}

void BasicAIModule::onUnitDestroy(BWAPI::Unit* unit)
{
  this->arbitrator.onRemoveObject(unit);
  this->buildManager->onRemoveUnit(unit);
  this->techManager->onRemoveUnit(unit);
  this->upgradeManager->onRemoveUnit(unit);
  this->workerManager->onRemoveUnit(unit);
  this->scoutManager->onRemoveUnit(unit);
}
bool BasicAIModule::onSendText(std::string text)
{
  UnitType type=UnitTypes::getUnitType(text);
  if (text=="debug")
  {
    this->showManagerAssignments=true;
    return true;
  }
  if (type!=UnitTypes::Unknown)
  {
    this->buildManager->build(type);
  }
  else
  {
    TechType type=TechTypes::getTechType(text);
    if (type!=TechTypes::Unknown)
    {
      this->techManager->research(type);
    }
    else
    {
      UpgradeType type=UpgradeTypes::getUpgradeType(text);
      if (type!=UpgradeTypes::Unknown)
      {
        this->upgradeManager->upgrade(type);
      }
      else
        Broodwar->printf("You typed '%s'!",text.c_str());
    }
  }
  return true;
}
<commit_msg>Removes the complete map information flag. It's serious business time!<commit_after>#include "BasicAIModule.h"
using namespace BWAPI;

void BasicAIModule::onStart()
{
  this->showManagerAssignments=false;
  if (Broodwar->isReplay()) return;
  // Enable some cheat flags
  Broodwar->enableFlag(Flag::UserInput);
  //Broodwar->enableFlag(Flag::CompleteMapInformation);
  BWTA::readMap();
  BWTA::analyze();
  this->analyzed=true;
  this->buildManager      = new BuildManager(&this->arbitrator);
  this->techManager       = new TechManager(&this->arbitrator);
  this->upgradeManager    = new UpgradeManager(&this->arbitrator);
  this->buildOrderManager = new BuildOrderManager(this->buildManager,this->techManager,this->upgradeManager);
  this->scoutManager      = new ScoutManager(&this->arbitrator);
  this->workerManager     = new WorkerManager(&this->arbitrator);
  this->baseManager       = new BaseManager();
  this->supplyManager     = new SupplyManager();

  this->supplyManager->setBuildManager(this->buildManager);
  this->supplyManager->setBuildOrderManager(this->buildOrderManager);
  this->techManager->setBuildingPlacer(this->buildManager->getBuildingPlacer());
  this->upgradeManager->setBuildingPlacer(this->buildManager->getBuildingPlacer());
  this->workerManager->setBaseManager(this->baseManager);
  this->baseManager->setBuildOrderManager(this->buildOrderManager);

  BWAPI::Race race = Broodwar->self()->getRace();
  BWAPI::UnitType workerType=*(race.getWorker());
  this->buildOrderManager->build(20,workerType,80);
  //make the basic production facility
  if (race == BWAPI::Races::Zerg)
  {
    //send an overlord out if Zerg
    this->scoutManager->setScoutCount(1);
    this->buildManager->build(BWAPI::UnitTypes::Zerg_Spawning_Pool);
    this->buildManager->build(BWAPI::UnitTypes::Zerg_Zergling);
    this->buildManager->build(BWAPI::UnitTypes::Zerg_Zergling);
    this->buildManager->build(BWAPI::UnitTypes::Zerg_Zergling);
  }
  else if (race == BWAPI::Races::Terran)
  {
    this->buildManager->build(BWAPI::UnitTypes::Terran_Barracks);
    this->buildManager->build(BWAPI::UnitTypes::Terran_Marine);
    this->buildManager->build(BWAPI::UnitTypes::Terran_Marine);
  }
  else if (race == BWAPI::Races::Protoss)
  {
    this->buildManager->build(BWAPI::UnitTypes::Protoss_Gateway);
    this->buildManager->build(BWAPI::UnitTypes::Protoss_Zealot);
  }

}

void BasicAIModule::onFrame()
{
  if (Broodwar->isReplay()) return;
  if (!this->analyzed) return;
  this->buildManager->update();
  this->buildOrderManager->update();
  this->baseManager->update();
  this->workerManager->update();
  this->techManager->update();
  this->upgradeManager->update();
  this->supplyManager->update();
  this->scoutManager->update();
  this->arbitrator.update();
  if (Broodwar->getFrameCount()>24*50)
    scoutManager->setScoutCount(1);

  std::set<Unit*> units=Broodwar->self()->getUnits();
  if (this->showManagerAssignments)
  {
    for(std::set<Unit*>::iterator i=units.begin();i!=units.end();i++)
    {
      if (this->arbitrator.hasBid(*i))
      {
        int x=(*i)->getPosition().x();
        int y=(*i)->getPosition().y();
        std::list< std::pair< Arbitrator::Controller<BWAPI::Unit*,double>*, double> > bids=this->arbitrator.getAllBidders(*i);
        int y_off=0;
        for(std::list< std::pair< Arbitrator::Controller<BWAPI::Unit*,double>*, double> >::iterator j=bids.begin();j!=bids.end();j++)
        {
          Broodwar->drawText(CoordinateType::Map,x,y+y_off,"%s: %d",j->first->getName().c_str(),(int)j->second);
          y_off+=20;
        }
      }
    }
  }
  /*
  for(std::set<Unit*>::iterator i=units.begin();i!=units.end();i++)
  {
    int x=(*i)->getPosition().x();
    int y=(*i)->getPosition().y();
    Broodwar->drawCircle(CoordinateType::Map,x,y,(*i)->getType().airWeapon()->maxRange(),Colors::Blue,false);
    Broodwar->drawCircle(CoordinateType::Map,x,y,(*i)->getType().groundWeapon()->maxRange(),Colors::Green,false);
  }
  */

  //we will iterate through all the base locations, and draw their outlines.
  for(std::set<BWTA::BaseLocation*>::const_iterator i=BWTA::getBaseLocations().begin();i!=BWTA::getBaseLocations().end();i++)
  {
    TilePosition p=(*i)->getTilePosition();
    Position c=(*i)->getPosition();

    //draw outline of center location
    Broodwar->drawBox(CoordinateType::Map,p.x()*32,p.y()*32,p.x()*32+4*32,p.y()*32+3*32,Colors::Blue,false);

    //draw a circle at each mineral patch
    for(std::set<BWAPI::Unit*>::const_iterator j=(*i)->getMinerals().begin();j!=(*i)->getMinerals().end();j++)
    {
      Position q=(*j)->getPosition();
      Broodwar->drawCircle(CoordinateType::Map,q.x(),q.y(),30,Colors::Cyan,false);
    }

    //draw the outlines of vespene geysers
    for(std::set<BWAPI::Unit*>::const_iterator j=(*i)->getGeysers().begin();j!=(*i)->getGeysers().end();j++)
    {
      TilePosition q=(*j)->getTilePosition();
      Broodwar->drawBox(CoordinateType::Map,q.x()*32,q.y()*32,q.x()*32+4*32,q.y()*32+2*32,Colors::Orange,false);
    }

    //if this is an island expansion, draw a yellow circle around the base location
    if ((*i)->isIsland())
    {
      Broodwar->drawCircle(CoordinateType::Map,c.x(),c.y(),80,Colors::Yellow,false);
    }
  }

  //we will iterate through all the regions and draw the polygon outline of it in green.
  for(std::set<BWTA::Region*>::const_iterator r=BWTA::getRegions().begin();r!=BWTA::getRegions().end();r++)
  {
    BWTA::Polygon p=(*r)->getPolygon();
    for(int j=0;j<(int)p.size();j++)
    {
      Position point1=p[j];
      Position point2=p[(j+1) % p.size()];
      Broodwar->drawLine(CoordinateType::Map,point1.x(),point1.y(),point2.x(),point2.y(),Colors::Green);
    }
  }

  //we will visualize the chokepoints with red lines
  for(std::set<BWTA::Region*>::const_iterator r=BWTA::getRegions().begin();r!=BWTA::getRegions().end();r++)
  {
    for(std::set<BWTA::Chokepoint*>::const_iterator c=(*r)->getChokepoints().begin();c!=(*r)->getChokepoints().end();c++)
    {
      Position point1=(*c)->getSides().first;
      Position point2=(*c)->getSides().second;
      Broodwar->drawLine(CoordinateType::Map,point1.x(),point1.y(),point2.x(),point2.y(),Colors::Red);
    }
  }
}

void BasicAIModule::onUnitDestroy(BWAPI::Unit* unit)
{
  this->arbitrator.onRemoveObject(unit);
  this->buildManager->onRemoveUnit(unit);
  this->techManager->onRemoveUnit(unit);
  this->upgradeManager->onRemoveUnit(unit);
  this->workerManager->onRemoveUnit(unit);
  this->scoutManager->onRemoveUnit(unit);
}
bool BasicAIModule::onSendText(std::string text)
{
  UnitType type=UnitTypes::getUnitType(text);
  if (text=="debug")
  {
    this->showManagerAssignments=true;
    return true;
  }
  if (type!=UnitTypes::Unknown)
  {
    this->buildManager->build(type);
  }
  else
  {
    TechType type=TechTypes::getTechType(text);
    if (type!=TechTypes::Unknown)
    {
      this->techManager->research(type);
    }
    else
    {
      UpgradeType type=UpgradeTypes::getUpgradeType(text);
      if (type!=UpgradeTypes::Unknown)
      {
        this->upgradeManager->upgrade(type);
      }
      else
        Broodwar->printf("You typed '%s'!",text.c_str());
    }
  }
  return true;
}
<|endoftext|>


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

Library:   TubeTK

Copyright 2010 Kitware Inc. 28 Corporate Drive,
Clifton Park, NY, 12065, USA.

All rights reserved.

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 <cstdlib>
#include <iostream>

#include <vnl/vnl_math.h>
#include <vcl_cmath.h>

#include "itkMacro.h"
#include "itkImage.h"
#include "itkImageRegionIteratorWithIndex.h"
#include "itkImageFileWriter.h"
#include "itkMersenneTwisterRandomVariateGenerator.h"

#include "../itkSplineND.h"
#include "../itkOptBrent1D.h"
#include "../itkSplineApproximation1D.h"
#include "../itkUserFunc.h"

class MySANDFunc:
  public itk::UserFunc< vnl_vector<int>, double >
  {
  private:
    double cVal;
  public:
    MySANDFunc( )
      {
      cVal = 0;
      };
    const double & value( const vnl_vector<int> & x )
      {
      cVal = vcl_sin((double)x[0]/2);
      cVal += vcl_cos((double)x[1]/2);
      std::cout << "s: x = " << x[0] << ", " << x[1]
        << " : v = " << cVal << std::endl;
      return cVal;
      };
  };

class MySANDFuncV:
  public itk::UserFunc< vnl_vector<double>, double >
  {
  private:
    double cVal;
  public:
    MySANDFuncV( )
      {
      cVal = 0;
      };
    const double & value( const vnl_vector<double> & x )
      {
      cVal = vcl_sin((double)x[0]/2);
      cVal += vcl_cos((double)x[1]/2);
      return cVal;
      };
  };
class MySANDFuncD:
  public itk::UserFunc< vnl_vector<double>, vnl_vector<double> >
  {
  private:
    vnl_vector<double> cDeriv;
  public:
    MySANDFuncD( )
      {
      cDeriv.set_size(2);
      cDeriv.fill( 0 );
      };
    const vnl_vector<double> & value( const vnl_vector<double> & x )
      {
      cDeriv[0] = vcl_cos((double)x[0]/2);
      cDeriv[1] = -vcl_sin((double)x[1]/2);
      return cDeriv;
      };
  };

int itkSplineNDTest( int argc, char *argv[] )
{
  if( argc != 2 )
    {
    std::cout << "usage: run <outImFile>" << std::endl;
    return EXIT_FAILURE;
    }

  double epsilon = 0.000001;

  MySANDFunc * myFunc = new MySANDFunc();
  MySANDFuncV * myFuncV = new MySANDFuncV();
  MySANDFuncD * myFuncD = new MySANDFuncD();

  itk::SplineApproximation1D * spline1D = new itk::SplineApproximation1D();

  itk::OptBrent1D * opt = new itk::OptBrent1D( );
  opt->smallDouble( epsilon );
  opt->searchForMin( true );
  opt->xStep( 0.01 );
  opt->tolerance( 0.0000001 );

  itk::SplineND spline( 2, myFunc, spline1D, opt );

  int returnStatus = EXIT_SUCCESS;

  spline.clipEdge( true );

  vnl_vector<int> xMin(2, -6);
  spline.xMin( xMin );
  if( spline.xMin()[0] != -6 )
    {
    std::cout << "xMin should be -6 and not " << spline.xMin() << std::endl;
    returnStatus = EXIT_FAILURE;
    }

  vnl_vector<int> xMax(2, 6);
  spline.xMax( xMax );
  if( spline.xMax()[0] != 6 )
    {
    std::cout << "xMax should be 6 and not " << spline.xMax() << std::endl;
    returnStatus = EXIT_FAILURE;
    }

  typedef itk::Image< float, 3 >  ImageType;

  ImageType::Pointer im = ImageType::New( );
  ImageType::RegionType imRegion;
  ImageType::SizeType imSize;
  imSize[0] = 60;
  imSize[1] = 60;
  imSize[2] = 20;
  imRegion.SetSize( imSize );
  ImageType::IndexType index0;
  index0[0] = -30;
  index0[1] = -30;
  index0[2] = -10;
  imRegion.SetIndex( index0 );
  im->SetRegions( imRegion );
  ImageType::SpacingType imSpacing;
  imSpacing[0] = 0.2;
  imSpacing[1] = 0.2;
  imSpacing[2] = 0.2;
  im->SetSpacing( imSpacing );
  im->Allocate( );

  itk::ImageRegionIteratorWithIndex<ImageType> itIm( im,
    im->GetLargestPossibleRegion( ) );
  ImageType::PointType pnt;
  itIm.GoToBegin();
  vnl_vector<double> x(2);
  vnl_vector<double> d(2);
  vnl_vector<int> di(2);
  di.fill( 0 );
  di[1] = 1;
  vnl_matrix<double> m(2,2);
  vnl_vector<double> d2(2);
  while( !itIm.IsAtEnd() )
    {
    im->TransformIndexToPhysicalPoint( itIm.GetIndex(), pnt );
    x[0] = pnt[0];
    x[1] = pnt[1];
    std::cout << "img: " << std::flush;
    switch( (itIm.GetIndex()[2] - index0[2]) % 9 )
      {
      default:
      case 0:
        {
        itIm.Set( spline.value(x) );
        break;
        }
      case 1:
        {
        itIm.Set( myFuncV->value(x) );
        break;
        }
      case 2:
        {
        itIm.Set( spline.valueD(x, di) );
        break;
        }
      case 3:
        {
        itIm.Set( myFuncD->value(x)[1] );
        break;
        }
      case 4:
        {
        d = spline.valueD(x);
        itIm.Set( d[0]*d[0] + d[1]*d[1] );
        break;
        }
      case 5:
        {
        d = myFuncD->value(x);
        itIm.Set( d[0]*d[0] + d[1]*d[1] );
        break;
        }
      case 6:
        {
        m = spline.hessian(x);
        itIm.Set( m[0][0]*m[0][0] + m[1][1]*m[1][1] );
        break;
        }
      case 7:
        {
        itIm.Set( spline.valueJet(x, d, m) );
        break;
        }
      case 8:
        {
        itIm.Set( spline.valueVDD2(x, d, d2) );
        break;
        }
      };
    ++itIm;
    }

  typedef itk::ImageFileWriter<ImageType> ImageWriterType;
  ImageWriterType::Pointer imWriter = ImageWriterType::New( );
  imWriter->SetFileName( argv[1] );
  imWriter->SetInput( im );
  imWriter->Update( );

  itk::Statistics::MersenneTwisterRandomVariateGenerator::Pointer rndGen
    = itk::Statistics::MersenneTwisterRandomVariateGenerator::New();
  rndGen->Initialize( 1 );

  int failed = 0;
  for(unsigned int c=0; c<100; c++)
    {
    x[0] = rndGen->GetNormalVariate( -1.0, 0.1 );
    x[1] = rndGen->GetNormalVariate( -1.0, 0.1 );
    std::cout << "Optimizing from " << x[0] << ", " << x[1] << std::endl;
    double xVal = 0;
    if( !spline.extreme( x, &xVal ) )
      {
      std::cout << "Spline.extreme failed." << std::endl;
      std::cout << "  x = " << x[0] << ", " << x[1] << std::endl;
      std::cout << "  xVal = " << xVal << std::endl;
      returnStatus = EXIT_FAILURE;
      ++failed;
      }
    else
      {
      bool err = false;
      if( x[0] != -1.5 || x[1] != -1.5 )
        {
        std::cout << "Spline.extreme failed." << std::endl;
        std::cout << "  x=" << x[0] << "," << x[1]
          << " != ideal=-1.5,-1.5" << std::endl;
        returnStatus = EXIT_FAILURE;
        err = true;
        }
      if( xVal != -0.8 )
        {
        std::cout << "Spline.extreme failed." << std::endl;
        std::cout << "  xVal=" << xVal << " != -0.8" << std::endl;
        returnStatus = EXIT_FAILURE;
        err = true;
        }
      if( err )
        {
        ++failed;
        }
      }
    }

  std::cout << failed << " out of 100 optimizations failed." << std::endl;

  return returnStatus;
}

<commit_msg>ENH: Fixed test of optimization using splines.   Specified proper target values.   Set optimization parameters for the ND optimizer, not for the 1D optimizer it uses.<commit_after>/*=========================================================================

Library:   TubeTK

Copyright 2010 Kitware Inc. 28 Corporate Drive,
Clifton Park, NY, 12065, USA.

All rights reserved.

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 <cstdlib>
#include <iostream>

#include <vnl/vnl_math.h>
#include <vcl_cmath.h>

#include "itkMacro.h"
#include "itkImage.h"
#include "itkImageRegionIteratorWithIndex.h"
#include "itkImageFileWriter.h"
#include "itkMersenneTwisterRandomVariateGenerator.h"

#include "../itkSplineND.h"
#include "../itkOptBrent1D.h"
#include "../itkOptParabolicFit1D.h"
#include "../itkSplineApproximation1D.h"
#include "../itkUserFunc.h"

class MySANDFunc:
  public itk::UserFunc< vnl_vector<int>, double >
  {
  private:
    double cVal;
  public:
    MySANDFunc( )
      {
      cVal = 0;
      };
    const double & value( const vnl_vector<int> & x )
      {
      cVal = vcl_sin((double)x[0]/2);
      cVal += vcl_cos((double)x[1]/2);
      std::cout << "s: x = " << x[0] << ", " << x[1]
        << " : v = " << cVal << std::endl;
      return cVal;
      };
  };

class MySANDFuncV:
  public itk::UserFunc< vnl_vector<double>, double >
  {
  private:
    double cVal;
  public:
    MySANDFuncV( )
      {
      cVal = 0;
      };
    const double & value( const vnl_vector<double> & x )
      {
      cVal = vcl_sin((double)x[0]/2);
      cVal += vcl_cos((double)x[1]/2);
      return cVal;
      };
  };
class MySANDFuncD:
  public itk::UserFunc< vnl_vector<double>, vnl_vector<double> >
  {
  private:
    vnl_vector<double> cDeriv;
  public:
    MySANDFuncD( )
      {
      cDeriv.set_size(2);
      cDeriv.fill( 0 );
      };
    const vnl_vector<double> & value( const vnl_vector<double> & x )
      {
      cDeriv[0] = vcl_cos((double)x[0]/2);
      cDeriv[1] = -vcl_sin((double)x[1]/2);
      return cDeriv;
      };
  };

int itkSplineNDTest( int argc, char *argv[] )
{
  if( argc != 2 )
    {
    std::cout << "usage: run <outImFile>" << std::endl;
    return EXIT_FAILURE;
    }

  MySANDFunc * myFunc = new MySANDFunc();
  MySANDFuncV * myFuncV = new MySANDFuncV();
  MySANDFuncD * myFuncD = new MySANDFuncD();

  itk::SplineApproximation1D * spline1D = new itk::SplineApproximation1D();

  //itk::OptParabolicFit1D * opt = new itk::OptParabolicFit1D( );
  itk::OptBrent1D * opt = new itk::OptBrent1D( );

  itk::SplineND spline( 2, myFunc, spline1D, opt );

  int returnStatus = EXIT_SUCCESS;

  spline.clipEdge( true );

  vnl_vector<int> xMin(2, -6);
  spline.xMin( xMin );
  if( spline.xMin()[0] != -6 )
    {
    std::cout << "xMin should be -6 and not " << spline.xMin() << std::endl;
    returnStatus = EXIT_FAILURE;
    }

  vnl_vector<int> xMax(2, 6);
  spline.xMax( xMax );
  if( spline.xMax()[0] != 6 )
    {
    std::cout << "xMax should be 6 and not " << spline.xMax() << std::endl;
    returnStatus = EXIT_FAILURE;
    }

  typedef itk::Image< float, 3 >  ImageType;

  ImageType::Pointer im = ImageType::New( );
  ImageType::RegionType imRegion;
  ImageType::SizeType imSize;
  imSize[0] = 60;
  imSize[1] = 60;
  imSize[2] = 20;
  imRegion.SetSize( imSize );
  ImageType::IndexType index0;
  index0[0] = -30;
  index0[1] = -30;
  index0[2] = -10;
  imRegion.SetIndex( index0 );
  im->SetRegions( imRegion );
  ImageType::SpacingType imSpacing;
  imSpacing[0] = 0.2;
  imSpacing[1] = 0.2;
  imSpacing[2] = 0.2;
  im->SetSpacing( imSpacing );
  im->Allocate( );

  itk::ImageRegionIteratorWithIndex<ImageType> itIm( im,
    im->GetLargestPossibleRegion( ) );
  ImageType::PointType pnt;
  itIm.GoToBegin();
  vnl_vector<double> x(2);
  vnl_vector<double> d(2);
  vnl_vector<int> di(2);
  di.fill( 0 );
  di[1] = 1;
  vnl_matrix<double> m(2,2);
  vnl_vector<double> d2(2);
  while( !itIm.IsAtEnd() )
    {
    im->TransformIndexToPhysicalPoint( itIm.GetIndex(), pnt );
    x[0] = pnt[0];
    x[1] = pnt[1];
    switch( (itIm.GetIndex()[2] - index0[2]) % 9 )
      {
      default:
      case 0:
        {
        itIm.Set( spline.value(x) );
        break;
        }
      case 1:
        {
        itIm.Set( myFuncV->value(x) );
        break;
        }
      case 2:
        {
        itIm.Set( spline.valueD(x, di) );
        break;
        }
      case 3:
        {
        itIm.Set( myFuncD->value(x)[1] );
        break;
        }
      case 4:
        {
        d = spline.valueD(x);
        itIm.Set( d[0] + d[1] );
        break;
        }
      case 5:
        {
        d = myFuncD->value(x);
        itIm.Set( d[0] + d[1] );
        break;
        }
      case 6:
        {
        m = spline.hessian(x);
        itIm.Set( m[0][0]*m[0][0] + m[1][1]*m[1][1] );
        break;
        }
      case 7:
        {
        itIm.Set( spline.valueJet(x, d, m) );
        break;
        }
      case 8:
        {
        itIm.Set( spline.valueVDD2(x, d, d2) );
        break;
        }
      };
    ++itIm;
    }

  typedef itk::ImageFileWriter<ImageType> ImageWriterType;
  ImageWriterType::Pointer imWriter = ImageWriterType::New( );
  imWriter->SetFileName( argv[1] );
  imWriter->SetInput( im );
  imWriter->Update( );

  itk::Statistics::MersenneTwisterRandomVariateGenerator::Pointer rndGen
    = itk::Statistics::MersenneTwisterRandomVariateGenerator::New();
  rndGen->Initialize( 1 );

  spline.optimizerND()->searchForMin( false );
  vnl_vector<double> xStep(2, 0.1);
  spline.optimizerND()->xStep( xStep );
  spline.optimizerND()->tolerance( 0.0001 );
  spline.optimizerND()->maxIterations( 1000 );
  spline.optimizerND()->maxLineSearches( 40 );
  if( opt->searchForMin() != false )
    {
    std::cout << "SearchForMin not preserved." << std::endl;
    returnStatus = EXIT_FAILURE;
    }
  if( opt->tolerance() != 0.0001 )
    {
    std::cout << "tolerance not preserved." << std::endl;
    returnStatus = EXIT_FAILURE;
    }
  opt->maxIterations( 1000 );
  if( opt->maxIterations() != 1000 )
    {
    std::cout << "maxIterations not preserved." << std::endl;
    returnStatus = EXIT_FAILURE;
    }
  int failed = 0;
  for(unsigned int c=0; c<100; c++)
    {
    x[0] = rndGen->GetNormalVariate( 3.14, 0.5 );
    x[1] = rndGen->GetNormalVariate( 0.0, 0.5 );
    std::cout << "Optimizing from " << x[0] << ", " << x[1] << std::endl;
    double xVal = 0;
    if( !spline.extreme( x, &xVal ) )
      {
      std::cout << "Spline.extreme failed." << std::endl;
      std::cout << "  x = " << x[0] << ", " << x[1] << std::endl;
      std::cout << "  xVal = " << xVal << std::endl;
      returnStatus = EXIT_FAILURE;
      ++failed;
      }
    else
      {
      bool err = false;
      if( vnl_math_abs(x[0] - 3.139) > 0.001
        || vnl_math_abs(x[1] - 0.0) > 0.001 )
        {
        std::cout << "Spline.extreme failed." << std::endl;
        std::cout << "  x = (" << x[0] << ", " << x[1]
          << ") != ideal = (3.1139, 0.0)" << std::endl;
        returnStatus = EXIT_FAILURE;
        err = true;
        }
      if( vnl_math_abs( xVal - 1.918) > 0.001 )
        {
        std::cout << "Spline.extreme failed." << std::endl;
        std::cout << "  xVal=" << xVal << " != 1.918" << std::endl;
        returnStatus = EXIT_FAILURE;
        err = true;
        }
      if( err )
        {
        ++failed;
        }
      else
        {
        std::cout << "Success: x = " << x << " : xVal = "
          << xVal << std::endl;
        }
      }
    }

  std::cout << failed << " out of 100 optimizations failed." << std::endl;

  return returnStatus;
}

<|endoftext|>


<commit_before>#include "GolfBall.hpp"
#include "../Resources.hpp"
#include "Default3D.vert.hpp"
#include "Default3D.geom.hpp"
#include "Default3D.frag.hpp"
#include "glm/gtc/constants.hpp"
#include "../Util/Log.hpp"
#include <glm/gtc/matrix_transform.hpp>
#include <glm/gtx/quaternion.hpp>

GolfBall::GolfBall(BallType ballType, TerrainObject* terrain, Water* water) : ModelObject(modelGeometry = Resources().CreateOBJModel("Resources/Models/GolfBall/GolfBall.obj"),
                                                                            "Resources/Models/GolfBall/Diffuse.png",
                                                                            "Resources/Models/GolfBall/Normal.png",
                                                                            "Resources/Models/GolfBall/Specular.png") {
    state = GolfBall::INITIAL;

    restitution = ballType == TWOPIECE ? 0.78f : 0.68f;
    this->terrain = terrain;
    this->water = water;
    origin = glm::vec3(1.f, 0.f, 1.f);

    mass = 0.0459f;
    this->ballType = ballType;

    sphere.position = Position();
    SetRadius(0.0214f);
}

GolfBall::~GolfBall() {
    Resources().FreeOBJModel(modelGeometry);
}

void GolfBall::Reset(glm::vec3 newOrigin){
    state = GolfBall::INITIAL;
    velocity = glm::vec3(0.f, 0.f, 0.f);
    angularVelocity = glm::vec3(0.f, 0.f, 0.f);
    SetPosition(newOrigin);
    sphere.position = Position();
    orientation = glm::quat();
}

void GolfBall::Render(Camera* camera, const glm::vec2& screenSize, const glm::vec4& clippingPlane) const{
    if (state != GolfBall::EXPLODED && state != GolfBall::OUT)
        ModelObject::Render(camera, screenSize, clippingPlane);
}

void GolfBall::Explode(std::vector<PlayerObject>& players){
    //@TODO: Set mass equivalent depending on material used.
    float equivalenceFactor = 1.0f;
    float massEquivalent = mass*equivalenceFactor;
    for (auto &player : players){
        glm::vec3 distanceV = (Position() - player.Position());
        float distance = glm::length(distanceV);
        //pow(meq, 1.f/3.f) => cube root of meq
        float z = distance / (pow(massEquivalent, 1.f / 3.f));
        float alpha = 1 + pow((z / 4.5f), 2.f);
        float beta = 1 + pow((z / 0.048f), 2.f);
        float gamma = 1 + pow((z / 1.35f), 2.f);
        float delta = 1 + pow((z / 0.32f), 2.f);
        //float Pf = 8.08f*pow(10.f, 7.f)*alpha;
		float Pf = ((8.08e7)*alpha) / sqrt(beta*gamma*delta);
        player.TakeDamage(Pf);
    }
    state = GolfBall::EXPLODED;
}

void GolfBall::Strike(ClubType club, const glm::vec3& clubVelocity) {
    state = GolfBall::ACTIVE;

    // Club velocity in strike plane.
    float v = glm::length(clubVelocity);
    if (v > 0.f)
    {
        float sinLoft = sin(club.loft);
        float cosLoft = cos(club.loft);

        // Ball velocity.
        float massCoefficient = club.mass / (club.mass + mass);
        float Up = (1.f + restitution) * massCoefficient * v * cosLoft;
        float Un = (2.f / 7.f) * massCoefficient * v * sinLoft;

        // Go back from strike plane to 3D.
        glm::vec3 forward = clubVelocity / v;
        glm::vec3 up = glm::cross(forward, glm::cross(glm::vec3(0.f, 1.f, 0.f), forward));
        glm::vec3 ep = glm::normalize(cosLoft * forward + sinLoft * up);
        glm::vec3 en = glm::normalize(sinLoft * forward - cosLoft * up);

        // Total velocity.
        velocity = Up * ep + Un * en;
        angularVelocity = -Un / sphere.radius * glm::cross(ep, en);
    } else {
        velocity = glm::vec3(0.f, 0.f, 0.f);
        angularVelocity = glm::vec3(0.f, 0.f, 0.f);
    }
}

float GolfBall::Radius() const {
    return sphere.radius;
}

void GolfBall::SetRadius(float radius) {
    sphere.radius = radius;
    SetScale(glm::vec3(radius, radius, radius));
    area = glm::pi<float>() * radius * radius;
}

glm::mat4 GolfBall::Orientation() const {
    return glm::toMat4(orientation);
}

GolfBall::State GolfBall::GetState() const {
    return state;
}
<commit_msg>Stuff<commit_after>#include "GolfBall.hpp"
#include "../Resources.hpp"
#include "Default3D.vert.hpp"
#include "Default3D.geom.hpp"
#include "Default3D.frag.hpp"
#include "glm/gtc/constants.hpp"
#include "../Util/Log.hpp"
#include <glm/gtc/matrix_transform.hpp>
#include <glm/gtx/quaternion.hpp>

GolfBall::GolfBall(BallType ballType, TerrainObject* terrain, Water* water) : ModelObject(modelGeometry = Resources().CreateOBJModel("Resources/Models/GolfBall/GolfBall.obj"),
                                                                            "Resources/Models/GolfBall/Diffuse.png",
                                                                            "Resources/Models/GolfBall/Normal.png",
                                                                            "Resources/Models/GolfBall/Specular.png") {
    state = GolfBall::INITIAL;

    restitution = ballType == TWOPIECE ? 0.78f : 0.68f;
    this->terrain = terrain;
    this->water = water;
    origin = glm::vec3(1.f, 0.f, 1.f);

    mass = 0.0459f;
    this->ballType = ballType;

    sphere.position = Position();
    SetRadius(0.0214f);
}

GolfBall::~GolfBall() {
    Resources().FreeOBJModel(modelGeometry);
}

void GolfBall::Reset(glm::vec3 newOrigin){
    state = GolfBall::INITIAL;
    velocity = glm::vec3(0.f, 0.f, 0.f);
    angularVelocity = glm::vec3(0.f, 0.f, 0.f);
    SetPosition(newOrigin);
    sphere.position = Position();
    orientation = glm::quat();
}

void GolfBall::Update(double time, const glm::vec3& wind, std::vector<PlayerObject>& players) {
	if (state == GolfBall::ACTIVE) {
		Move(static_cast<float>(time)* velocity);
		sphere.position = Position();

		if (glm::length(angularVelocity) > 0.0001f) {
			glm::quat deltaQuat = glm::angleAxis(static_cast<float>(time)* glm::length(angularVelocity), glm::normalize(angularVelocity));
			orientation = deltaQuat * orientation;
		}

		glm::vec3 dragForce, magnusForce, acceleration = glm::vec3(0.f, 0.f, 0.f);

		float groundLevel = terrain->GetY(Position().x, Position().z);
		float waterLevel = water->Position().y;

		// Check if in water.
		if ((sphere.position.y - sphere.radius < groundLevel && groundLevel + sphere.radius < waterLevel) || sphere.position.y + sphere.radius < waterLevel) {
			state = GolfBall::OUT;
			return;
		}

		// Check for collision
		if ((sphere.position.y - sphere.radius) < groundLevel){
			float vCritical = 1.8f;
			float e = 0.35f;
			float muSliding = 0.51f;
			float muRolling = 0.096f;
			SetPosition(Position().x, groundLevel + sphere.radius, Position().z);
			sphere.position = Position();
			glm::vec3 eRoh = glm::normalize(terrain->GetNormal(Position().x, Position().z));
			glm::vec3 tangentialVelocity = velocity - glm::dot(velocity, eRoh) * eRoh;
			glm::vec3 eFriction = glm::vec3(0.f, 0.f, 0.f);
			if (glm::length(glm::cross(eRoh, angularVelocity) + tangentialVelocity) > 0.0001f){
				eFriction = glm::normalize(sphere.radius * glm::cross(eRoh, angularVelocity) + tangentialVelocity);
			}
			float vRoh = glm::dot(velocity, eRoh);
			float deltaU = -(e + 1.f) * vRoh;

			if (vRoh < vCritical && glm::length(tangentialVelocity) > 0.0001f) {
				glm::vec3 mg = (9.82f*glm::vec3(0.f, -1.f, 0.f));
				glm::vec3 tangentialGravityAcceleration = mg - glm::dot(mg, eRoh)*eRoh;
				glm::vec3 compareVectorPositive = eFriction - normalize(tangentialVelocity);
				glm::vec3 compareVectorNegative = eFriction - normalize(-tangentialVelocity);
				if ((glm::length(compareVectorNegative) < 0.03f) || (glm::length(compareVectorPositive) < 0.03f)) {
					//sliding
					glm::vec3 tangentialSlidingFrictionDeceleration = muSliding*eFriction*9.82f*mass*eRoh.y;
					float alpha = (glm::length(tangentialSlidingFrictionDeceleration)*sphere.radius) / (mass*sphere.radius*sphere.radius*0.4f);
					velocity = velocity + (tangentialSlidingFrictionDeceleration + tangentialGravityAcceleration)*static_cast<float>(time);
					glm::vec3 tangentialVelocityDirection = glm::normalize(velocity);
					angularVelocity = angularVelocity + (alpha*static_cast<float>(time))*(glm::cross(sphere.radius*tangentialVelocityDirection, -eRoh));
				}
				else {
					//rolling
					glm::vec3 tangentialRollingFrictionDeceleration = muRolling*eFriction*9.82f*mass*eRoh.y;
					velocity = velocity + (tangentialRollingFrictionDeceleration + tangentialGravityAcceleration)*static_cast<float>(time);
					glm::vec3 tangentialVelocityDirection = glm::normalize(velocity);
					angularVelocity = (glm::length(velocity) / sphere.radius)*(glm::cross(eFriction, -eRoh));
				}
			}
			else {
				float deltaTime = pow(mass * mass / (fabs(vRoh) * sphere.radius), 0.2f) * 0.00251744f;
				float velocityRoh = glm::dot(velocity, eRoh);
				float velocityNormal = glm::dot(velocity, eFriction);
				float uRoh = -e*velocityRoh;
				float deltauRoh = uRoh - (velocityRoh);
				float deltaUn = muSliding*deltauRoh;
				float rollUn = (5.f / 7.f)*velocityNormal;
				float slideUn = velocityNormal - deltaUn;

				if (velocityNormal > rollUn){
					velocity = uRoh*eRoh + rollUn*eFriction;
					angularVelocity += muRolling * (deltaU + 9.82f*eRoh.y * deltaTime) / sphere.radius * glm::cross(eRoh, eFriction);
				}
				else {
					velocity = uRoh*eRoh + slideUn*eFriction;
					angularVelocity += muSliding * (deltaU + 9.82f *eRoh.y* deltaTime) / sphere.radius * glm::cross(eRoh, eFriction);
				}
			}
		}
		else {
			// Calculate magnus force.
			float v = glm::length(velocity);
			float u = glm::length(velocity - wind);
			float w = glm::length(angularVelocity);
			glm::vec3 eU = (velocity - wind) / u;
			magnusForce = glm::vec3(0.f, 0.f, 0.f);
			if (u > 0.f && v > 0.f && w > 0.f) {
				float Cm = (sqrt(1.f + 0.31f * (w / v)) - 1.f) / 20.f;
				float Fm = 0.5f * Cm * 1.23f * area * u * u;
				magnusForce = Fm * glm::cross(eU, glm::normalize(angularVelocity));
			}

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

			// Calculate gravitational force.
			glm::vec3 gravitationForce = glm::vec3(0.f, mass * -9.82f, 0.f);
			// Get acceleration from total force.
			acceleration = (dragForce + magnusForce + gravitationForce) / mass;
			velocity += acceleration * static_cast<float>(time);
		}
	}
}

void GolfBall::Render(Camera* camera, const glm::vec2& screenSize, const glm::vec4& clippingPlane) const{
    if (state != GolfBall::EXPLODED && state != GolfBall::OUT)
        ModelObject::Render(camera, screenSize, clippingPlane);
}

void GolfBall::Explode(std::vector<PlayerObject>& players){
    //@TODO: Set mass equivalent depending on material used.
    float equivalenceFactor = 1.0f;
    float massEquivalent = mass*equivalenceFactor;
    for (auto &player : players){
        glm::vec3 distanceV = (Position() - player.Position());
        float distance = glm::length(distanceV);
        //pow(meq, 1.f/3.f) => cube root of meq
        float z = distance / (pow(massEquivalent, 1.f / 3.f));
        float alpha = 1 + pow((z / 4.5f), 2.f);
        float beta = 1 + pow((z / 0.048f), 2.f);
        float gamma = 1 + pow((z / 1.35f), 2.f);
        float delta = 1 + pow((z / 0.32f), 2.f);
        //float Pf = 8.08f*pow(10.f, 7.f)*alpha;
		float Pf = ((8.08e7)*alpha) / sqrt(beta*gamma*delta);
        player.TakeDamage(Pf);
    }
    state = GolfBall::EXPLODED;
}

void GolfBall::Strike(ClubType club, const glm::vec3& clubVelocity) {
    state = GolfBall::ACTIVE;

    // Club velocity in strike plane.
    float v = glm::length(clubVelocity);
    if (v > 0.f)
    {
        float sinLoft = sin(club.loft);
        float cosLoft = cos(club.loft);

        // Ball velocity.
        float massCoefficient = club.mass / (club.mass + mass);
        float Up = (1.f + restitution) * massCoefficient * v * cosLoft;
        float Un = (2.f / 7.f) * massCoefficient * v * sinLoft;

        // Go back from strike plane to 3D.
        glm::vec3 forward = clubVelocity / v;
        glm::vec3 up = glm::cross(forward, glm::cross(glm::vec3(0.f, 1.f, 0.f), forward));
        glm::vec3 ep = glm::normalize(cosLoft * forward + sinLoft * up);
        glm::vec3 en = glm::normalize(sinLoft * forward - cosLoft * up);

        // Total velocity.
        velocity = Up * ep + Un * en;
        angularVelocity = -Un / sphere.radius * glm::cross(ep, en);
    } else {
        velocity = glm::vec3(0.f, 0.f, 0.f);
        angularVelocity = glm::vec3(0.f, 0.f, 0.f);
    }
}

float GolfBall::Radius() const {
    return sphere.radius;
}

void GolfBall::SetRadius(float radius) {
    sphere.radius = radius;
    SetScale(glm::vec3(radius, radius, radius));
    area = glm::pi<float>() * radius * radius;
}

glm::mat4 GolfBall::Orientation() const {
    return glm::toMat4(orientation);
}

GolfBall::State GolfBall::GetState() const {
    return state;
}
<|endoftext|>


<commit_before>#include "GolfBall.hpp"
#include "../Resources.hpp"
#include "Default3D.vert.hpp"
#include "Default3D.geom.hpp"
#include "Default3D.frag.hpp"
#include "glm/gtc/constants.hpp"
#include "../Util/Log.hpp"
#include <glm/gtc/matrix_transform.hpp>
#include <glm/gtx/quaternion.hpp>

GolfBall::GolfBall(BallType ballType, TerrainObject* terrain, Water* water) : ModelObject(modelGeometry = Resources().CreateOBJModel("Resources/Models/GolfBall/GolfBall.obj"),
                                                                            "Resources/Models/GolfBall/Diffuse.png",
                                                                            "Resources/Models/GolfBall/Normal.png",
                                                                            "Resources/Models/GolfBall/Specular.png") {
    state = GolfBall::INITIAL;

    restitution = ballType == TWOPIECE ? 0.78f : 0.68f;
    this->terrain = terrain;
    this->water = water;
    origin = glm::vec3(1.f, 0.f, 1.f);

    mass = 0.0459f;
    this->ballType = ballType;

    sphere.position = Position();
    SetRadius(0.0214f);
}

GolfBall::~GolfBall() {
    Resources().FreeOBJModel(modelGeometry);
}

void GolfBall::Reset(){
    state = GolfBall::INITIAL;
    velocity = glm::vec3(0.f, 0.f, 0.f);
    angularVelocity = glm::vec3(0.f, 0.f, 0.f);
    SetPosition(origin);
    sphere.position = Position();
    orientation = glm::quat();
}

void GolfBall::Update(double time, const glm::vec3& wind, std::vector<PlayerObject>& players) {
	if (state == GolfBall::ACTIVE) {
		Move(static_cast<float>(time)* velocity);
		sphere.position = Position();

		if (glm::length(angularVelocity) > 0.0001f) {
			glm::quat deltaQuat = glm::angleAxis(static_cast<float>(time)* glm::length(angularVelocity), glm::normalize(angularVelocity));
			orientation = deltaQuat * orientation;
		}

		glm::vec3 dragForce, magnusForce = glm::vec3(0.f, 0.f, 0.f);

		float groundLevel = terrain->GetY(Position().x, Position().z);
        float waterLevel = water->Position().y;

        // Check if in water.
        if ((sphere.position.y - sphere.radius < groundLevel && groundLevel + sphere.radius < waterLevel) || sphere.position.y + sphere.radius < waterLevel) {
            state = GolfBall::OUT;
            return;
        }

        // Check for collision
		if (glm::length(velocity) > 0.0001f && (sphere.position.y - sphere.radius) < groundLevel){
			float vCritical = 0.3f;
			float e = 0.35f;
			float muSliding = 0.51f;
			float muRolling = 0.096f;
			SetPosition(Position().x, groundLevel + sphere.radius, Position().z);
			sphere.position = Position();
			//glm::vec3 eRoh = glm::normalize(glm::vec3(0.f, 1.f, 0.f));
			glm::vec3 eRoh = terrain->GetNormal(Position().x, Position().z);
			glm::vec3 tangentialVelocity = velocity - glm::dot(velocity, eRoh) * eRoh;
			glm::vec3 eFriction = glm::vec3(0.f, 0.f, 0.f);
			if (glm::length(glm::cross(eRoh, angularVelocity) + tangentialVelocity) > 0.0001f){
				eFriction = glm::normalize(sphere.radius * glm::cross(eRoh, angularVelocity) + tangentialVelocity);
			}
			float vRoh = glm::dot(velocity, eRoh);
			float deltaU = -(e + 1.f) * vRoh;
			glm::vec3 angularDirection = glm::cross(eRoh, glm::normalize(tangentialVelocity));
			float w = glm::dot(angularVelocity, angularDirection);

			if (fabs(vRoh) < vCritical && glm::length(tangentialVelocity) > 0.0001f) {
				glm::vec3 mg = (9.82f)*glm::vec3(0.f, -1.f, 0.f);
				glm::vec3 tangentialGravityAcceleration = glm::dot(mg, eRoh)*eRoh;
				glm::vec3 tangentialSlidingFrictionDeceleration = muSliding*eFriction;
				glm::vec3 tangentialRolling = (5.f/7.f)*tangentialVelocity;
				glm::vec3 tangentialDelta = tangentialVelocity + (tangentialGravityAcceleration - tangentialSlidingFrictionDeceleration)*static_cast<float>(time);
				if (w * sphere.radius + 0.0001f < glm::length(tangentialVelocity)) {
					//Rolling
					velocity = tangentialVelocity - tangentialRolling*static_cast<float>(time);
					angularVelocity = (glm::length(velocity) / sphere.radius) * cross(eRoh,eFriction);
				} else {
					//Sliding
					velocity = tangentialVelocity - (tangentialGravityAcceleration - tangentialSlidingFrictionDeceleration)*static_cast<float>(time);
					angularVelocity += (5.f / 2.f) * (muSliding * 9.82f / sphere.radius * static_cast<float>(time)) * cross(eRoh, eFriction);
				}
			} else {
				float deltaTime = pow(mass * mass / (fabs(vRoh) * sphere.radius), 0.2f) * 0.00251744f;
				float velocityRoh = glm::dot(velocity, eRoh);
				float velocityNormal = glm::dot(velocity, eFriction);
				float uRoh = -e*velocityRoh;
				float deltauRoh = uRoh - (velocityRoh);
				float deltaUn = muSliding*deltauRoh;
				float rollUn = (5.f / 7.f)*velocityNormal;
				float slideUn = velocityNormal - deltaUn;

				if (velocityNormal > rollUn){
					velocity = uRoh*eRoh + rollUn*eFriction;
					angularVelocity += muRolling * (deltaU + 9.82f*eRoh.y * deltaTime) / sphere.radius * glm::cross(eRoh, eFriction);
				} else {
					velocity = uRoh*eRoh + slideUn*eFriction;
					angularVelocity += muSliding * (deltaU + 9.82f *eRoh.y* deltaTime) / sphere.radius * glm::cross(eRoh, eFriction);
				}
			}
		} else {
			// Calculate magnus force.
			float v = glm::length(velocity);
			float u = glm::length(velocity - wind);
			float w = glm::length(angularVelocity);
			glm::vec3 eU = (velocity - wind) / u;
			magnusForce = glm::vec3(0.f, 0.f, 0.f);
			if (u > 0.f && v > 0.f && w > 0.f) {
				float Cm = (sqrt(1.f + 0.31f * (w / v)) - 1.f) / 20.f;
				float Fm = 0.5f * Cm * 1.23f * area * u * u;
				magnusForce = Fm * glm::cross(eU, glm::normalize(angularVelocity));
			}

			// Calculate drag force.
			float cD;
			if (ballType == TWOPIECE)
				cD = v < 65.f ? -0.0051f * v + 0.53f : 0.21f;
			else
				cD = v < 60.f ? -0.0084f * v + 0.73f : 0.22f;
			dragForce = glm::vec3(0.f, 0.f, 0.f);
			if (u > 0.f)
				dragForce = -0.5f * 1.23f * area * cD * u * u * eU;
		}
		// Calculate gravitational force.
		glm::vec3 gravitationForce = glm::vec3(0.f, mass * -9.82f, 0.f);
		// Get acceleration from total force.
		glm::vec3 acceleration = (dragForce + magnusForce + gravitationForce) / mass;
		velocity += acceleration * static_cast<float>(time);

	}
}

void GolfBall::Render(Camera* camera, const glm::vec2& screenSize, const glm::vec4& clippingPlane) const{
    if (state != GolfBall::EXPLODED && state != GolfBall::OUT)
        ModelObject::Render(camera, screenSize, clippingPlane);
}

void GolfBall::Explode(std::vector<PlayerObject>& players){
    //@TODO: Set mass equivalent depending on material used.
    float equivalenceFactor = 1.0f;
    float massEquivalent = mass*equivalenceFactor;
    for (auto &player : players){
        glm::vec3 distanceV = (Position() - player.Position());
        float distance = glm::length(distanceV);
        //pow(meq, 1.f/3.f) => cube root of meq
        float z = distance / (pow(massEquivalent, 1.f / 3.f));
        float alpha = 1 + pow((z / 4.5f), 2.f);
        float beta = 1 + pow((z / 0.048f), 2.f);
        float gamma = 1 + pow((z / 1.35f), 2.f);
        float delta = 1 + pow((z / 0.32f), 2.f);
        //float Pf = 8.08f*pow(10.f, 7.f)*alpha;
		float Pf = ((8.08e7)*alpha) / sqrt(beta*gamma*delta);
        player.TakeDamage(Pf);
    }
    state = GolfBall::EXPLODED;
}

void GolfBall::Strike(ClubType club, const glm::vec3& clubVelocity) {
    state = GolfBall::ACTIVE;

    // Club velocity in strike plane.
    float v = glm::length(clubVelocity);
    if (v > 0.f)
    {
        float sinLoft = sin(club.loft);
        float cosLoft = cos(club.loft);

        // Ball velocity.
        float massCoefficient = club.mass / (club.mass + mass);
        float Up = (1.f + restitution) * massCoefficient * v * cosLoft;
        float Un = (2.f / 7.f) * massCoefficient * v * sinLoft;

        // Go back from strike plane to 3D.
        glm::vec3 forward = clubVelocity / v;
        glm::vec3 up = glm::cross(forward, glm::cross(glm::vec3(0.f, 1.f, 0.f), forward));
        glm::vec3 ep = glm::normalize(cosLoft * forward + sinLoft * up);
        glm::vec3 en = glm::normalize(sinLoft * forward - cosLoft * up);

        // Total velocity.
        velocity = Up * ep + Un * en;
        angularVelocity = -Un / sphere.radius * glm::cross(ep, en);
    } else {
        velocity = glm::vec3(0.f, 0.f, 0.f);
        angularVelocity = glm::vec3(0.f, 0.f, 0.f);
    }
}

float GolfBall::Radius() const {
    return sphere.radius;
}

void GolfBall::SetRadius(float radius) {
    sphere.radius = radius;
    SetScale(glm::vec3(radius, radius, radius));
    area = glm::pi<float>() * radius * radius;
}

glm::mat4 GolfBall::Orientation() const {
    return glm::toMat4(orientation);
}

GolfBall::State GolfBall::GetState() const {
    return state;
}
<commit_msg>More work on friction<commit_after>#include "GolfBall.hpp"
#include "../Resources.hpp"
#include "Default3D.vert.hpp"
#include "Default3D.geom.hpp"
#include "Default3D.frag.hpp"
#include "glm/gtc/constants.hpp"
#include "../Util/Log.hpp"
#include <glm/gtc/matrix_transform.hpp>
#include <glm/gtx/quaternion.hpp>

GolfBall::GolfBall(BallType ballType, TerrainObject* terrain, Water* water) : ModelObject(modelGeometry = Resources().CreateOBJModel("Resources/Models/GolfBall/GolfBall.obj"),
                                                                            "Resources/Models/GolfBall/Diffuse.png",
                                                                            "Resources/Models/GolfBall/Normal.png",
                                                                            "Resources/Models/GolfBall/Specular.png") {
    state = GolfBall::INITIAL;

    restitution = ballType == TWOPIECE ? 0.78f : 0.68f;
    this->terrain = terrain;
    this->water = water;
    origin = glm::vec3(1.f, 0.f, 1.f);

    mass = 0.0459f;
    this->ballType = ballType;

    sphere.position = Position();
    SetRadius(0.0214f);
}

GolfBall::~GolfBall() {
    Resources().FreeOBJModel(modelGeometry);
}

void GolfBall::Reset(){
    state = GolfBall::INITIAL;
    velocity = glm::vec3(0.f, 0.f, 0.f);
    angularVelocity = glm::vec3(0.f, 0.f, 0.f);
    SetPosition(origin);
    sphere.position = Position();
    orientation = glm::quat();
}

void GolfBall::Update(double time, const glm::vec3& wind, std::vector<PlayerObject>& players) {
	if (state == GolfBall::ACTIVE) {
		Move(static_cast<float>(time)* velocity);
		sphere.position = Position();

		if (glm::length(angularVelocity) > 0.0001f) {
			glm::quat deltaQuat = glm::angleAxis(static_cast<float>(time)* glm::length(angularVelocity), glm::normalize(angularVelocity));
			orientation = deltaQuat * orientation;
		}

		glm::vec3 dragForce, magnusForce = glm::vec3(0.f, 0.f, 0.f);

		float groundLevel = terrain->GetY(Position().x, Position().z);
        float waterLevel = water->Position().y;

        // Check if in water.
        if ((sphere.position.y - sphere.radius < groundLevel && groundLevel + sphere.radius < waterLevel) || sphere.position.y + sphere.radius < waterLevel) {
            state = GolfBall::OUT;
            return;
        }

        // Check for collision
		if (glm::length(velocity) > 0.0001f && (sphere.position.y - sphere.radius) < groundLevel){
			float vCritical = 0.3f;
			float e = 0.35f;
			float muSliding = 0.51f;
			float muRolling = 0.096f;
			SetPosition(Position().x, groundLevel + sphere.radius, Position().z);
			sphere.position = Position();
			//glm::vec3 eRoh = glm::normalize(glm::vec3(0.f, 1.f, 0.f));
			glm::vec3 eRoh = terrain->GetNormal(Position().x, Position().z);
			glm::vec3 tangentialVelocity = velocity - glm::dot(velocity, eRoh) * eRoh;
			glm::vec3 eFriction = glm::vec3(0.f, 0.f, 0.f);
			if (glm::length(glm::cross(eRoh, angularVelocity) + tangentialVelocity) > 0.0001f){
				eFriction = glm::normalize(sphere.radius * glm::cross(eRoh, angularVelocity) + tangentialVelocity);
			}
			float vRoh = glm::dot(velocity, eRoh);
			float deltaU = -(e + 1.f) * vRoh;
			glm::vec3 angularDirection = glm::cross(eRoh, glm::normalize(tangentialVelocity));
			float w = glm::dot(angularVelocity, angularDirection);

			if (fabs(vRoh) < vCritical && glm::length(tangentialVelocity) > 0.0001f) {
				glm::vec3 mg = (9.82f)*glm::vec3(0.f, -1.f, 0.f);
				glm::vec3 tangentialGravityAcceleration = glm::dot(mg, eRoh)*eRoh;
				glm::vec3 tangentialSlidingFrictionDeceleration = muSliding*eFriction;
				glm::vec3 tangentialRollingFrictionDeceleration = muRolling*eFriction;
				glm::vec3 tangentialDelta = tangentialVelocity + (tangentialGravityAcceleration - tangentialSlidingFrictionDeceleration)*static_cast<float>(time);
				if (w * sphere.radius + 0.0001f < glm::length(tangentialVelocity)) {
					//Rolling
					velocity = tangentialVelocity + (tangentialGravityAcceleration - tangentialRollingFrictionDeceleration)*static_cast<float>(time);
					angularVelocity = (glm::length(velocity) / sphere.radius) * cross(eRoh,eFriction);
				} else {
					//Sliding
					velocity = tangentialVelocity + (tangentialGravityAcceleration - tangentialSlidingFrictionDeceleration)*static_cast<float>(time);
					angularVelocity += (5.f / 2.f) * (muSliding * 9.82f / sphere.radius * static_cast<float>(time)) * cross(eRoh, eFriction);
				}
			} else {
				float deltaTime = pow(mass * mass / (fabs(vRoh) * sphere.radius), 0.2f) * 0.00251744f;
				float velocityRoh = glm::dot(velocity, eRoh);
				float velocityNormal = glm::dot(velocity, eFriction);
				float uRoh = -e*velocityRoh;
				float deltauRoh = uRoh - (velocityRoh);
				float deltaUn = muSliding*deltauRoh;
				float rollUn = (5.f / 7.f)*velocityNormal;
				float slideUn = velocityNormal - deltaUn;

				if (velocityNormal > rollUn){
					velocity = uRoh*eRoh + rollUn*eFriction;
					angularVelocity += muRolling * (deltaU + 9.82f*eRoh.y * deltaTime) / sphere.radius * glm::cross(eRoh, eFriction);
				} else {
					velocity = uRoh*eRoh + slideUn*eFriction;
					angularVelocity += muSliding * (deltaU + 9.82f *eRoh.y* deltaTime) / sphere.radius * glm::cross(eRoh, eFriction);
				}
			}
		} else {
			// Calculate magnus force.
			float v = glm::length(velocity);
			float u = glm::length(velocity - wind);
			float w = glm::length(angularVelocity);
			glm::vec3 eU = (velocity - wind) / u;
			magnusForce = glm::vec3(0.f, 0.f, 0.f);
			if (u > 0.f && v > 0.f && w > 0.f) {
				float Cm = (sqrt(1.f + 0.31f * (w / v)) - 1.f) / 20.f;
				float Fm = 0.5f * Cm * 1.23f * area * u * u;
				magnusForce = Fm * glm::cross(eU, glm::normalize(angularVelocity));
			}

			// Calculate drag force.
			float cD;
			if (ballType == TWOPIECE)
				cD = v < 65.f ? -0.0051f * v + 0.53f : 0.21f;
			else
				cD = v < 60.f ? -0.0084f * v + 0.73f : 0.22f;
			dragForce = glm::vec3(0.f, 0.f, 0.f);
			if (u > 0.f)
				dragForce = -0.5f * 1.23f * area * cD * u * u * eU;
		}
		// Calculate gravitational force.
		glm::vec3 gravitationForce = glm::vec3(0.f, mass * -9.82f, 0.f);
		// Get acceleration from total force.
		glm::vec3 acceleration = (dragForce + magnusForce + gravitationForce) / mass;
		velocity += acceleration * static_cast<float>(time);

	}
}

void GolfBall::Render(Camera* camera, const glm::vec2& screenSize, const glm::vec4& clippingPlane) const{
    if (state != GolfBall::EXPLODED && state != GolfBall::OUT)
        ModelObject::Render(camera, screenSize, clippingPlane);
}

void GolfBall::Explode(std::vector<PlayerObject>& players){
    //@TODO: Set mass equivalent depending on material used.
    float equivalenceFactor = 1.0f;
    float massEquivalent = mass*equivalenceFactor;
    for (auto &player : players){
        glm::vec3 distanceV = (Position() - player.Position());
        float distance = glm::length(distanceV);
        //pow(meq, 1.f/3.f) => cube root of meq
        float z = distance / (pow(massEquivalent, 1.f / 3.f));
        float alpha = 1 + pow((z / 4.5f), 2.f);
        float beta = 1 + pow((z / 0.048f), 2.f);
        float gamma = 1 + pow((z / 1.35f), 2.f);
        float delta = 1 + pow((z / 0.32f), 2.f);
        //float Pf = 8.08f*pow(10.f, 7.f)*alpha;
		float Pf = ((8.08e7)*alpha) / sqrt(beta*gamma*delta);
        player.TakeDamage(Pf);
    }
    state = GolfBall::EXPLODED;
}

void GolfBall::Strike(ClubType club, const glm::vec3& clubVelocity) {
    state = GolfBall::ACTIVE;

    // Club velocity in strike plane.
    float v = glm::length(clubVelocity);
    if (v > 0.f)
    {
        float sinLoft = sin(club.loft);
        float cosLoft = cos(club.loft);

        // Ball velocity.
        float massCoefficient = club.mass / (club.mass + mass);
        float Up = (1.f + restitution) * massCoefficient * v * cosLoft;
        float Un = (2.f / 7.f) * massCoefficient * v * sinLoft;

        // Go back from strike plane to 3D.
        glm::vec3 forward = clubVelocity / v;
        glm::vec3 up = glm::cross(forward, glm::cross(glm::vec3(0.f, 1.f, 0.f), forward));
        glm::vec3 ep = glm::normalize(cosLoft * forward + sinLoft * up);
        glm::vec3 en = glm::normalize(sinLoft * forward - cosLoft * up);

        // Total velocity.
        velocity = Up * ep + Un * en;
        angularVelocity = -Un / sphere.radius * glm::cross(ep, en);
    } else {
        velocity = glm::vec3(0.f, 0.f, 0.f);
        angularVelocity = glm::vec3(0.f, 0.f, 0.f);
    }
}

float GolfBall::Radius() const {
    return sphere.radius;
}

void GolfBall::SetRadius(float radius) {
    sphere.radius = radius;
    SetScale(glm::vec3(radius, radius, radius));
    area = glm::pi<float>() * radius * radius;
}

glm::mat4 GolfBall::Orientation() const {
    return glm::toMat4(orientation);
}

GolfBall::State GolfBall::GetState() const {
    return state;
}
<|endoftext|>


<commit_before>#include <iomanip>

#include "battleship.hpp"

const char  HIT = 'h',
            MISS = 'm',
            EMPTY = ' ',
            HORIZONTAL = 'H',
            VERTICAL = 'V';

const int HITCHANCENORMAL = 20;
const int HITCHANCEHARD = 30;
const int HITCHANCEEXTREME = 40;

bool debug = false;

const pair<string, int> SHIPTYPES[] =
{
    // Pairing ship names with lengths
    pair<string, int>("Carrier", 5),
    pair<string, int>("Battleship", 4),
    pair<string, int>("Cruiser", 3),
    pair<string, int>("Submarine", 3),
    pair<string, int>("Destroyer", 2)
};

const string title = "  ██████╗  █████╗ ████████╗████████╗██╗     ███████╗███████╗██╗  ██╗██╗██████╗ \n  ██╔══██╗██╔══██╗╚══██╔══╝╚══██╔══╝██║     ██╔════╝██╔════╝██║  ██║██║██╔══██╗\n  ██████╔╝███████║   ██║      ██║   ██║     █████╗  ███████╗███████║██║██████╔╝\n  ██╔══██╗██╔══██║   ██║      ██║   ██║     ██╔══╝  ╚════██║██╔══██║██║██╔═══╝ \n  ██████╔╝██║  ██║   ██║      ██║   ███████╗███████╗███████║██║  ██║██║██║     \n  ╚═════╝ ╚═╝  ╚═╝   ╚═╝      ╚═╝   ╚══════╝╚══════╝╚══════╝╚═╝  ╚═╝╚═╝╚═╝     \n                                                                               \n";

int getMenuChoice(int numChoices, string message)
{
    int choice; // Holds user's choice
    bool valid = false;

    cout << message;

    do
    {
        // Keep asking for choice until a valid choice is made
        cout << "\n> ";

        if (cin >> choice)
        {
            if (choice >= 1 && choice <= numChoices)
            {
                valid = true; // If the input is an int and within the limit, it's
                // valid
            }
        }

        cin.clear();
        cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');

        if (!valid)
        {
            cout << "\nPlease select a choice from the menu.";
        }

    } while (!valid);

    return choice;
}

string getStringInput()
{
    // Returns a string given by user
    string input;
    getline(cin, input);
    return input;
}

string toLowercase(string s)
{
    // Converts all uppercase letters in a string to lowercase letters
    for (auto c : s)
    {
        c = tolower(c);
    }

    return s;
}

void clearScreen()
{
    // Outputs a bunch of newlines, effectively "clearing" the screen
    int count = 500;

    if (debug)
    {
        count = 5;
    }

    while (count > 0)
    {
        cout << endl;
        count--;
    }
}

int getShipLengthFromName(string name)
{
    // We try to match the name given to our ship to a ship in our SHIPS array
    // so we can set our ship to the desired length.
    bool validName = false;
    int length = 0;

    for (auto ship : SHIPTYPES)
    {
        if (ship.first == name)
        {
            length = ship.second;
            validName = true;
        }
    }

    // If the name given doesn't match up to anything, that's bad, m'kay.
    if (!validName)
    {
        throw ExceptionInvalidShipName();
    }

    return length;
}

void displayTitle()
{
    if (!debug)
    {
        clearScreen();
        cout << title;
        cout << std::setw(44) << "Cody Kelly" << endl;
        cout << std::setw(43) << "© 2017" << endl << endl;
        cout << "Press enter to continue.\n\n";
        cin.get();
    }
}

std::ostream& operator<< (std::ostream& os, const Coordinate c)
{
    os << char(c.x + 'A') << c.y + 1;

    return os;
}
<commit_msg>Added <limits><commit_after>#include <iomanip>
#include <limits>

#include "battleship.hpp"

const char  HIT = 'h',
            MISS = 'm',
            EMPTY = ' ',
            HORIZONTAL = 'H',
            VERTICAL = 'V';

const int HITCHANCENORMAL = 20;
const int HITCHANCEHARD = 30;
const int HITCHANCEEXTREME = 40;

bool debug = false;

const pair<string, int> SHIPTYPES[] =
{
    // Pairing ship names with lengths
    pair<string, int>("Carrier", 5),
    pair<string, int>("Battleship", 4),
    pair<string, int>("Cruiser", 3),
    pair<string, int>("Submarine", 3),
    pair<string, int>("Destroyer", 2)
};

const string title = "  ██████╗  █████╗ ████████╗████████╗██╗     ███████╗███████╗██╗  ██╗██╗██████╗ \n  ██╔══██╗██╔══██╗╚══██╔══╝╚══██╔══╝██║     ██╔════╝██╔════╝██║  ██║██║██╔══██╗\n  ██████╔╝███████║   ██║      ██║   ██║     █████╗  ███████╗███████║██║██████╔╝\n  ██╔══██╗██╔══██║   ██║      ██║   ██║     ██╔══╝  ╚════██║██╔══██║██║██╔═══╝ \n  ██████╔╝██║  ██║   ██║      ██║   ███████╗███████╗███████║██║  ██║██║██║     \n  ╚═════╝ ╚═╝  ╚═╝   ╚═╝      ╚═╝   ╚══════╝╚══════╝╚══════╝╚═╝  ╚═╝╚═╝╚═╝     \n                                                                               \n";

int getMenuChoice(int numChoices, string message)
{
    int choice; // Holds user's choice
    bool valid = false;

    cout << message;

    do
    {
        // Keep asking for choice until a valid choice is made
        cout << "\n> ";

        if (cin >> choice)
        {
            if (choice >= 1 && choice <= numChoices)
            {
                valid = true; // If the input is an int and within the limit, it's
                // valid
            }
        }

        cin.clear();
        cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');

        if (!valid)
        {
            cout << "\nPlease select a choice from the menu.";
        }

    } while (!valid);

    return choice;
}

string getStringInput()
{
    // Returns a string given by user
    string input;
    getline(cin, input);
    return input;
}

string toLowercase(string s)
{
    // Converts all uppercase letters in a string to lowercase letters
    for (auto c : s)
    {
        c = tolower(c);
    }

    return s;
}

void clearScreen()
{
    // Outputs a bunch of newlines, effectively "clearing" the screen
    int count = 500;

    if (debug)
    {
        count = 5;
    }

    while (count > 0)
    {
        cout << endl;
        count--;
    }
}

int getShipLengthFromName(string name)
{
    // We try to match the name given to our ship to a ship in our SHIPS array
    // so we can set our ship to the desired length.
    bool validName = false;
    int length = 0;

    for (auto ship : SHIPTYPES)
    {
        if (ship.first == name)
        {
            length = ship.second;
            validName = true;
        }
    }

    // If the name given doesn't match up to anything, that's bad, m'kay.
    if (!validName)
    {
        throw ExceptionInvalidShipName();
    }

    return length;
}

void displayTitle()
{
    if (!debug)
    {
        clearScreen();
        cout << title;
        cout << std::setw(44) << "Cody Kelly" << endl;
        cout << std::setw(43) << "© 2017" << endl << endl;
        cout << "Press enter to continue.\n\n";
        cin.get();
    }
}

std::ostream& operator<< (std::ostream& os, const Coordinate c)
{
    os << char(c.x + 'A') << c.y + 1;

    return os;
}
<|endoftext|>