<commit_before>/*
*
* Copyright 2013 Telefonica Investigacion y Desarrollo, S.A.U
*
* This file is part of Orion Context Broker.
*
* Orion Context Broker is free software: you can redistribute it and/or
* modify it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* Orion Context Broker is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero
* General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with Orion Context Broker. If not, see http://www.gnu.org/licenses/.
*
* For those usages not covered by this license please contact with
* iot_support at tid dot es
*
* Author: Fermin Galan
*/

#include <vector>

#include <curl/curl.h>

#include "logMsg/logMsg.h"
#include "logMsg/traceLevels.h"

#include "common/string.h"
#include "common/statistics.h"
#include "common/limits.h"
#include "common/RenderFormat.h"
#include "common/macroSubstitute.h"
#include "alarmMgr/alarmMgr.h"
#include "apiTypesV2/HttpInfo.h"
#include "ngsi10/NotifyContextRequest.h"
#include "rest/httpRequestSend.h"
#include "ngsiNotify/senderThread.h"
#include "ngsiNotify/Notifier.h"

/* ****************************************************************************
*
* ~Notifier -
*/
Notifier::~Notifier (void)
{
  // FIXME: This destructor is needed to avoid warning message.
  // Compilation fails when a warning occurs, and it is enabled
  // compilation option -Werror "warnings being treated as errors"
  LM_T(LmtNotImplemented, ("Notifier destructor is not implemented"));
}

/* ****************************************************************************
*
* Notifier::sendNotifyContextRequest -
*/
void Notifier::sendNotifyContextRequest
(
    NotifyContextRequest*            ncrP,
    const ngsiv2::HttpInfo&          httpInfo,
    const std::string&               tenant,
    const std::string&               xauthToken,
    const std::string&               fiwareCorrelator,
    RenderFormat                     renderFormat,
    const std::vector<std::string>&  attrsOrder,
    const std::vector<std::string>&  metadataFilter,
    bool                             blackList
    )
{

  pthread_t                         tid;
  std::vector<SenderThreadParams*>  *paramsV = Notifier::buildSenderParams(ncrP, httpInfo, tenant, xauthToken, fiwareCorrelator, renderFormat, attrsOrder, metadataFilter, blackList);

  if (!paramsV->empty()) // al least one param, an empty vector means an error happened
  {
    int ret = pthread_create(&tid, NULL, startSenderThread, paramsV);
    if (ret != 0)
    {
      LM_E(("Runtime Error (error creating thread: %d)", ret));
      for (unsigned ix = 0; ix < paramsV->size(); ix++)
      {
        delete (*paramsV)[ix];
      }
      delete paramsV;
      return;
    }
    pthread_detach(tid);
  }
}

/* ****************************************************************************
*
* Notifier::sendNotifyContextAvailabilityRequest -
*
* FIXME: this method is very similar to sendNotifyContextRequest and probably
* they could be refactored in the future to have a common part using a parent
* class for both types of notifications and using it as first argument
*/
void Notifier::sendNotifyContextAvailabilityRequest
(
  NotifyContextAvailabilityRequest*  ncar,
  const std::string&                 url,
  const std::string&                 tenant,
  const std::string&                 fiwareCorrelator,
  RenderFormat                       renderFormat
)
{
    /* Render NotifyContextAvailabilityRequest */
    std::string payload = ncar->render(NotifyContextAvailability, "");

    /* Parse URL */
    std::string  host;
    int          port;
    std::string  uriPath;
    std::string  protocol;

    if (!parseUrl(url, host, port, uriPath, protocol))
    {
      std::string details = std::string("sending NotifyContextAvailabilityRequest: malformed URL: '") + url + "'";
      alarmMgr.badInput(clientIp, details);

      return;
    }

    /* Set Content-Type */
    std::string content_type = "application/json";

    /* Send the message (without awaiting response, in a separate thread to avoid blocking) */
    pthread_t            tid;
    SenderThreadParams*  params = new SenderThreadParams();

    params->ip               = host;
    params->port             = port;
    params->verb             = "POST";
    params->tenant           = tenant;
    params->resource         = uriPath;
    params->content_type     = content_type;
    params->content          = payload;
    params->mimeType         = JSON;
    params->fiwareCorrelator = fiwareCorrelator;
    params->renderFormat     = renderFormatToString(renderFormat);

    strncpy(params->transactionId, transactionId, sizeof(params->transactionId));

    std::vector<SenderThreadParams*>* paramsV = new std::vector<SenderThreadParams*>;
    paramsV->push_back(params);

    int ret = pthread_create(&tid, NULL, startSenderThread, paramsV);
    if (ret != 0)
    {
      LM_E(("Runtime Error (error creating thread: %d)", ret));
      return;
    }
    pthread_detach(tid);
}

/* ****************************************************************************
*
* buildSenderParamsCustom -
*
*/
static std::vector<SenderThreadParams*>* buildSenderParamsCustom
(
    const SubscriptionId&                subscriptionId,
    const ContextElementResponseVector&  cv,
    const ngsiv2::HttpInfo&              httpInfo,
    const std::string&                   tenant,
    const std::string&                   xauthToken,
    const std::string&                   fiwareCorrelator,
    RenderFormat                         renderFormat,
    const std::vector<std::string>&      attrsOrder,
    const std::vector<std::string>&      metadataFilter
    )
{

  std::vector<SenderThreadParams*>*   paramsV;

  paramsV = new std::vector<SenderThreadParams*>;

  for (unsigned ix = 0; ix < cv.size(); ix++)
  {
    Verb                                verb    = httpInfo.verb;
    std::string                         method;
    std::string                         url;
    std::string                         payload;
    std::string                         mimeType;
    std::map<std::string, std::string>  qs;
    std::map<std::string, std::string>  headers;
    const ContextElement&               ce      = cv[ix]->contextElement;

    //
    // 1. Verb/Method
    //
    if (verb == NOVERB)
    {
      // Default verb/method is POST
      verb = POST;
    }
    method = verbName(verb);

    //
    // 2. URL
    //
    macroSubstitute(&url, httpInfo.url, ce);

    //
    // 3. Payload
    //

    if (httpInfo.payload == "")
    {
      NotifyContextRequest   ncr;
      ContextElementResponse cer;

      cer.contextElement = ce;
      ncr.subscriptionId = subscriptionId;
      ncr.contextElementResponseVector.push_back(&cer);
      payload  = ncr.toJson(renderFormat, attrsOrder, metadataFilter);
      mimeType = "application/json";
    }
    else
    {
      macroSubstitute(&payload, httpInfo.payload, ce);
      char* pload  = curl_unescape(payload.c_str(), payload.length());
      payload      = std::string(pload);
      renderFormat = NGSI_V2_CUSTOM;
      mimeType     = "text/plain";  // May be overridden by 'Content-Type' in 'headers'
      free(pload);
    }

    //
    // 4. URI Params (Query Strings)
    //
    for (std::map<std::string, std::string>::const_iterator it = httpInfo.qs.begin(); it != httpInfo.qs.end(); ++it)
    {
      std::string key   = it->first;
      std::string value = it->second;

      macroSubstitute(&key,   it->first, ce);
      macroSubstitute(&value, it->second, ce);
      if ((value == "") || (key == ""))
      {
        // To avoid e.g '?a=&b=&c='
        continue;
      }
      qs[key] = value;
    }

    //
    // 5. HTTP Headers
    //
    for (std::map<std::string, std::string>::const_iterator it = httpInfo.headers.begin(); it != httpInfo.headers.end(); ++it)
    {
      std::string key   = it->first;
      std::string value = it->second;

      macroSubstitute(&key,   it->first, ce);
      macroSubstitute(&value, it->second, ce);

      if (key == "")
      {
        // To avoid empty header name
        continue;
      }

      headers[key] = value;
    }

    //
    // 6. Split URI in protocol, host, port and path
    //
    std::string  protocol;
    std::string  host;
    int          port;
    std::string  uriPath;

    if (!parseUrl(url, host, port, uriPath, protocol))
    {
      LM_E(("Runtime Error (not sending NotifyContextRequest: malformed URL: '%s')", httpInfo.url.c_str()));
      return paramsV;  //empty vector
    }

    //
    // 7. Add URI params from template to uriPath
    //
    std::string  uri = uriPath;

    if (qs.size() != 0)
    {
      uri += "?";

      int ix = 0;
      for (std::map<std::string, std::string>::iterator it = qs.begin(); it != qs.end(); ++it)
      {
        if (ix != 0)
        {
          uri += "&";
        }

        uri += it->first + "=" + it->second;
        ++ix;
      }
    }

    SenderThreadParams *params = new SenderThreadParams();

    params->ip               = host;
    params->port             = port;
    params->protocol         = protocol;
    params->verb             = method;
    params->tenant           = tenant;
    params->servicePath      = ce.entityId.servicePath;
    params->xauthToken       = xauthToken;
    params->resource         = uri;
    params->content_type     = mimeType;
    params->content          = payload;
    params->mimeType         = JSON;
    params->renderFormat     = renderFormatToString(renderFormat);
    params->fiwareCorrelator = fiwareCorrelator;
    params->extraHeaders     = headers;

    paramsV->push_back(params);
  }

  return paramsV;
}

/* ****************************************************************************
*
* Notifier::buildSenderParams -
*/
std::vector<SenderThreadParams*>* Notifier::buildSenderParams
(
  NotifyContextRequest*            ncrP,
  const ngsiv2::HttpInfo&          httpInfo,
  const std::string&               tenant,
  const std::string&               xauthToken,
  const std::string&               fiwareCorrelator,
  RenderFormat                     renderFormat,
  const std::vector<std::string>&  attrsOrder,
  const std::vector<std::string>&  metadataFilter,
  bool                             blackList
)
{
    ConnectionInfo                    ci;
    Verb                              verb = httpInfo.verb;
    std::vector<SenderThreadParams*>* paramsV = new std::vector<SenderThreadParams*>();

    if ((verb == NOVERB) || (verb == UNKNOWNVERB) || disableCusNotif)
    {
      // Default verb/method (or the one in case of disabled custom notifications) is POST
      verb = POST;
    }

    //
    // If any of the 'template parameters' is used by the subscripion, then it is not a question of an ordinary notification but one using templates.
    // Ordinary notifications are simply sent, all of it as one message.
    //
    // Notifications for subscriptions using templates are more complex:
    //   - if there is more than one entity for the notification, split into N notifications, one per entity
    //   - if 'url' contains substitution keys, substitute the keys for their current values
    //   - if 'qs' contains query strings, add this to 'url', with the proper substitutions done
    //   - if 'headers' is non-empty, perform eventual substitutions and make sure the information is added as HTTP headers for the notification
    //   - if 'payload' is given, use that string as template instead of the default payload string, substituting all fields that are to be substituted
    //   - if 'method' is given, then a custom HTTP method is used (instead of POST, which is default)
    //
    //
    // Note that disableCusNotif (taken from CLI) could disable custom notifications and force to use regular ones
    //
    if (httpInfo.custom && !disableCusNotif)
    {

        return buildSenderParamsCustom(ncrP->subscriptionId,
                       ncrP->contextElementResponseVector,
                       httpInfo,
                       tenant,
                       xauthToken,
                       fiwareCorrelator,
                       renderFormat,
                       attrsOrder,
                       metadataFilter);
    }

    //
    // Creating the value of the Fiware-ServicePath HTTP header.
    // This is a comma-separated list of the service-paths in the same order as the entities come in the payload
    //
    std::string spathList;
    bool        atLeastOneNotDefault = false;

    for (unsigned int ix = 0; ix < ncrP->contextElementResponseVector.size(); ++ix)
    {
      EntityId* eP = &ncrP->contextElementResponseVector[ix]->contextElement.entityId;

      if (spathList != "")
      {
        spathList += ",";
      }
      spathList += eP->servicePath;
      atLeastOneNotDefault = atLeastOneNotDefault || (eP->servicePath != "/");
    }

    //
    // FIXME P8: the stuff about atLeastOneNotDefault was added after PR #729, which makes "/" the default servicePath in
    // request not having that header. However, this causes as side-effect that a
    // "Fiware-ServicePath: /" or "Fiware-ServicePath: /,/" header is added in notifications, thus breaking several tests harness.
    // Given that the "clean" implementation of Fiware-ServicePath propagation will be implemented
    // soon (it has been scheduled for version 0.19.0, see https://github.com/telefonicaid/fiware-orion/issues/714)
    // we introduce the atLeastOneNotDefault hack. Once #714 gets implemented,
    // this FIXME will be removed (and all the test harness adjusted, if needed)
    //
    if (!atLeastOneNotDefault)
    {
      spathList = "";
    }

    ci.outMimeType = JSON;

    std::string payloadString;
    if (renderFormat == NGSI_V1_LEGACY)
    {
      payloadString = ncrP->render(&ci, NotifyContext, "");
    }
    else
    {
      payloadString = ncrP->toJson(renderFormat, attrsOrder, metadataFilter, blackList);
    }

    /* Parse URL */
    std::string  host;
    int          port;
    std::string  uriPath;
    std::string  protocol;

    if (!parseUrl(httpInfo.url, host, port, uriPath, protocol))
    {
      LM_E(("Runtime Error (not sending NotifyContextRequest: malformed URL: '%s')", httpInfo.url.c_str()));
      return paramsV;  //empty vector
    }

    /* Set Content-Type */
    std::string content_type = "application/json";

    SenderThreadParams*  params = new SenderThreadParams();

    params->ip               = host;
    params->port             = port;
    params->protocol         = protocol;
    params->verb             = verbName(verb);
    params->tenant           = tenant;
    params->servicePath      = spathList;
    params->xauthToken       = xauthToken;
    params->resource         = uriPath;
    params->content_type     = content_type;
    params->content          = payloadString;
    params->mimeType         = JSON;
    params->renderFormat     = renderFormatToString(renderFormat);
    params->fiwareCorrelator = fiwareCorrelator;

    // Cuidadito con esto
    strncpy(params->transactionId, transactionId, sizeof(params->transactionId));

    paramsV->push_back(params);
    return paramsV;

}

<commit_msg>Fix memory leak<commit_after>/*
*
* Copyright 2013 Telefonica Investigacion y Desarrollo, S.A.U
*
* This file is part of Orion Context Broker.
*
* Orion Context Broker is free software: you can redistribute it and/or
* modify it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* Orion Context Broker is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero
* General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with Orion Context Broker. If not, see http://www.gnu.org/licenses/.
*
* For those usages not covered by this license please contact with
* iot_support at tid dot es
*
* Author: Fermin Galan
*/

#include <vector>

#include <curl/curl.h>

#include "logMsg/logMsg.h"
#include "logMsg/traceLevels.h"

#include "common/string.h"
#include "common/statistics.h"
#include "common/limits.h"
#include "common/RenderFormat.h"
#include "common/macroSubstitute.h"
#include "alarmMgr/alarmMgr.h"
#include "apiTypesV2/HttpInfo.h"
#include "ngsi10/NotifyContextRequest.h"
#include "rest/httpRequestSend.h"
#include "ngsiNotify/senderThread.h"
#include "ngsiNotify/Notifier.h"

/* ****************************************************************************
*
* ~Notifier -
*/
Notifier::~Notifier (void)
{
  // FIXME: This destructor is needed to avoid warning message.
  // Compilation fails when a warning occurs, and it is enabled
  // compilation option -Werror "warnings being treated as errors"
  LM_T(LmtNotImplemented, ("Notifier destructor is not implemented"));
}

/* ****************************************************************************
*
* Notifier::sendNotifyContextRequest -
*/
void Notifier::sendNotifyContextRequest
(
    NotifyContextRequest*            ncrP,
    const ngsiv2::HttpInfo&          httpInfo,
    const std::string&               tenant,
    const std::string&               xauthToken,
    const std::string&               fiwareCorrelator,
    RenderFormat                     renderFormat,
    const std::vector<std::string>&  attrsOrder,
    const std::vector<std::string>&  metadataFilter,
    bool                             blackList
    )
{

  pthread_t                         tid;
  std::vector<SenderThreadParams*>  *paramsV = Notifier::buildSenderParams(ncrP, httpInfo, tenant, xauthToken, fiwareCorrelator, renderFormat, attrsOrder, metadataFilter, blackList);

  if (!paramsV->empty()) // al least one param, an empty vector means an error happened
  {
    int ret = pthread_create(&tid, NULL, startSenderThread, paramsV);
    if (ret != 0)
    {
      LM_E(("Runtime Error (error creating thread: %d)", ret));
      for (unsigned ix = 0; ix < paramsV->size(); ix++)
      {
        delete (*paramsV)[ix];
      }
      delete paramsV;
      return;
    }
    pthread_detach(tid);
  }
}

/* ****************************************************************************
*
* Notifier::sendNotifyContextAvailabilityRequest -
*
* FIXME: this method is very similar to sendNotifyContextRequest and probably
* they could be refactored in the future to have a common part using a parent
* class for both types of notifications and using it as first argument
*/
void Notifier::sendNotifyContextAvailabilityRequest
(
  NotifyContextAvailabilityRequest*  ncar,
  const std::string&                 url,
  const std::string&                 tenant,
  const std::string&                 fiwareCorrelator,
  RenderFormat                       renderFormat
)
{
    /* Render NotifyContextAvailabilityRequest */
    std::string payload = ncar->render(NotifyContextAvailability, "");

    /* Parse URL */
    std::string  host;
    int          port;
    std::string  uriPath;
    std::string  protocol;

    if (!parseUrl(url, host, port, uriPath, protocol))
    {
      std::string details = std::string("sending NotifyContextAvailabilityRequest: malformed URL: '") + url + "'";
      alarmMgr.badInput(clientIp, details);

      return;
    }

    /* Set Content-Type */
    std::string content_type = "application/json";

    /* Send the message (without awaiting response, in a separate thread to avoid blocking) */
    pthread_t            tid;
    SenderThreadParams*  params = new SenderThreadParams();

    params->ip               = host;
    params->port             = port;
    params->verb             = "POST";
    params->tenant           = tenant;
    params->resource         = uriPath;
    params->content_type     = content_type;
    params->content          = payload;
    params->mimeType         = JSON;
    params->fiwareCorrelator = fiwareCorrelator;
    params->renderFormat     = renderFormatToString(renderFormat);

    strncpy(params->transactionId, transactionId, sizeof(params->transactionId));

    std::vector<SenderThreadParams*>* paramsV = new std::vector<SenderThreadParams*>;
    paramsV->push_back(params);

    int ret = pthread_create(&tid, NULL, startSenderThread, paramsV);
    if (ret != 0)
    {
      LM_E(("Runtime Error (error creating thread: %d)", ret));
      return;
    }
    pthread_detach(tid);
}

/* ****************************************************************************
*
* buildSenderParamsCustom -
*
*/
static std::vector<SenderThreadParams*>* buildSenderParamsCustom
(
    const SubscriptionId&                subscriptionId,
    const ContextElementResponseVector&  cv,
    const ngsiv2::HttpInfo&              httpInfo,
    const std::string&                   tenant,
    const std::string&                   xauthToken,
    const std::string&                   fiwareCorrelator,
    RenderFormat                         renderFormat,
    const std::vector<std::string>&      attrsOrder,
    const std::vector<std::string>&      metadataFilter
    )
{

  std::vector<SenderThreadParams*>*   paramsV;

  paramsV = new std::vector<SenderThreadParams*>;

  for (unsigned ix = 0; ix < cv.size(); ix++)
  {
    Verb                                verb    = httpInfo.verb;
    std::string                         method;
    std::string                         url;
    std::string                         payload;
    std::string                         mimeType;
    std::map<std::string, std::string>  qs;
    std::map<std::string, std::string>  headers;
    const ContextElement&               ce      = cv[ix]->contextElement;

    //
    // 1. Verb/Method
    //
    if (verb == NOVERB)
    {
      // Default verb/method is POST
      verb = POST;
    }
    method = verbName(verb);

    //
    // 2. URL
    //
    macroSubstitute(&url, httpInfo.url, ce);

    //
    // 3. Payload
    //

    if (httpInfo.payload == "")
    {
      NotifyContextRequest   ncr;
      ContextElementResponse cer;

      cer.contextElement = ce;
      ncr.subscriptionId = subscriptionId;
      ncr.contextElementResponseVector.push_back(&cer);
      payload  = ncr.toJson(renderFormat, attrsOrder, metadataFilter);
      mimeType = "application/json";
    }
    else
    {
      macroSubstitute(&payload, httpInfo.payload, ce);
      char* pload  = curl_unescape(payload.c_str(), payload.length());
      payload      = std::string(pload);
      renderFormat = NGSI_V2_CUSTOM;
      mimeType     = "text/plain";  // May be overridden by 'Content-Type' in 'headers'
      free(pload);
    }

    //
    // 4. URI Params (Query Strings)
    //
    for (std::map<std::string, std::string>::const_iterator it = httpInfo.qs.begin(); it != httpInfo.qs.end(); ++it)
    {
      std::string key   = it->first;
      std::string value = it->second;

      macroSubstitute(&key,   it->first, ce);
      macroSubstitute(&value, it->second, ce);
      if ((value == "") || (key == ""))
      {
        // To avoid e.g '?a=&b=&c='
        continue;
      }
      qs[key] = value;
    }

    //
    // 5. HTTP Headers
    //
    for (std::map<std::string, std::string>::const_iterator it = httpInfo.headers.begin(); it != httpInfo.headers.end(); ++it)
    {
      std::string key   = it->first;
      std::string value = it->second;

      macroSubstitute(&key,   it->first, ce);
      macroSubstitute(&value, it->second, ce);

      if (key == "")
      {
        // To avoid empty header name
        continue;
      }

      headers[key] = value;
    }

    //
    // 6. Split URI in protocol, host, port and path
    //
    std::string  protocol;
    std::string  host;
    int          port;
    std::string  uriPath;

    if (!parseUrl(url, host, port, uriPath, protocol))
    {
      LM_E(("Runtime Error (not sending NotifyContextRequest: malformed URL: '%s')", httpInfo.url.c_str()));
      return paramsV;  //empty vector
    }

    //
    // 7. Add URI params from template to uriPath
    //
    std::string  uri = uriPath;

    if (qs.size() != 0)
    {
      uri += "?";

      int ix = 0;
      for (std::map<std::string, std::string>::iterator it = qs.begin(); it != qs.end(); ++it)
      {
        if (ix != 0)
        {
          uri += "&";
        }

        uri += it->first + "=" + it->second;
        ++ix;
      }
    }

    SenderThreadParams *params = new SenderThreadParams();

    params->ip               = host;
    params->port             = port;
    params->protocol         = protocol;
    params->verb             = method;
    params->tenant           = tenant;
    params->servicePath      = ce.entityId.servicePath;
    params->xauthToken       = xauthToken;
    params->resource         = uri;
    params->content_type     = mimeType;
    params->content          = payload;
    params->mimeType         = JSON;
    params->renderFormat     = renderFormatToString(renderFormat);
    params->fiwareCorrelator = fiwareCorrelator;
    params->extraHeaders     = headers;

    paramsV->push_back(params);
  }

  return paramsV;
}

/* ****************************************************************************
*
* Notifier::buildSenderParams -
*/
std::vector<SenderThreadParams*>* Notifier::buildSenderParams
(
  NotifyContextRequest*            ncrP,
  const ngsiv2::HttpInfo&          httpInfo,
  const std::string&               tenant,
  const std::string&               xauthToken,
  const std::string&               fiwareCorrelator,
  RenderFormat                     renderFormat,
  const std::vector<std::string>&  attrsOrder,
  const std::vector<std::string>&  metadataFilter,
  bool                             blackList
)
{
    ConnectionInfo                    ci;
    Verb                              verb    = httpInfo.verb;
    std::vector<SenderThreadParams*>* paramsV = NULL;

    if ((verb == NOVERB) || (verb == UNKNOWNVERB) || disableCusNotif)
    {
      // Default verb/method (or the one in case of disabled custom notifications) is POST
      verb = POST;
    }

    //
    // If any of the 'template parameters' is used by the subscripion, then it is not a question of an ordinary notification but one using templates.
    // Ordinary notifications are simply sent, all of it as one message.
    //
    // Notifications for subscriptions using templates are more complex:
    //   - if there is more than one entity for the notification, split into N notifications, one per entity
    //   - if 'url' contains substitution keys, substitute the keys for their current values
    //   - if 'qs' contains query strings, add this to 'url', with the proper substitutions done
    //   - if 'headers' is non-empty, perform eventual substitutions and make sure the information is added as HTTP headers for the notification
    //   - if 'payload' is given, use that string as template instead of the default payload string, substituting all fields that are to be substituted
    //   - if 'method' is given, then a custom HTTP method is used (instead of POST, which is default)
    //
    //
    // Note that disableCusNotif (taken from CLI) could disable custom notifications and force to use regular ones
    //
    if (httpInfo.custom && !disableCusNotif)
    {

        return buildSenderParamsCustom(ncrP->subscriptionId,
                       ncrP->contextElementResponseVector,
                       httpInfo,
                       tenant,
                       xauthToken,
                       fiwareCorrelator,
                       renderFormat,
                       attrsOrder,
                       metadataFilter);
    }

    paramsV = new std::vector<SenderThreadParams*>();

    //
    // Creating the value of the Fiware-ServicePath HTTP header.
    // This is a comma-separated list of the service-paths in the same order as the entities come in the payload
    //
    std::string spathList;
    bool        atLeastOneNotDefault = false;

    for (unsigned int ix = 0; ix < ncrP->contextElementResponseVector.size(); ++ix)
    {
      EntityId* eP = &ncrP->contextElementResponseVector[ix]->contextElement.entityId;

      if (spathList != "")
      {
        spathList += ",";
      }
      spathList += eP->servicePath;
      atLeastOneNotDefault = atLeastOneNotDefault || (eP->servicePath != "/");
    }

    //
    // FIXME P8: the stuff about atLeastOneNotDefault was added after PR #729, which makes "/" the default servicePath in
    // request not having that header. However, this causes as side-effect that a
    // "Fiware-ServicePath: /" or "Fiware-ServicePath: /,/" header is added in notifications, thus breaking several tests harness.
    // Given that the "clean" implementation of Fiware-ServicePath propagation will be implemented
    // soon (it has been scheduled for version 0.19.0, see https://github.com/telefonicaid/fiware-orion/issues/714)
    // we introduce the atLeastOneNotDefault hack. Once #714 gets implemented,
    // this FIXME will be removed (and all the test harness adjusted, if needed)
    //
    if (!atLeastOneNotDefault)
    {
      spathList = "";
    }

    ci.outMimeType = JSON;

    std::string payloadString;
    if (renderFormat == NGSI_V1_LEGACY)
    {
      payloadString = ncrP->render(&ci, NotifyContext, "");
    }
    else
    {
      payloadString = ncrP->toJson(renderFormat, attrsOrder, metadataFilter, blackList);
    }

    /* Parse URL */
    std::string  host;
    int          port;
    std::string  uriPath;
    std::string  protocol;

    if (!parseUrl(httpInfo.url, host, port, uriPath, protocol))
    {
      LM_E(("Runtime Error (not sending NotifyContextRequest: malformed URL: '%s')", httpInfo.url.c_str()));
      return paramsV;  //empty vector
    }

    /* Set Content-Type */
    std::string content_type = "application/json";

    SenderThreadParams*  params = new SenderThreadParams();

    params->ip               = host;
    params->port             = port;
    params->protocol         = protocol;
    params->verb             = verbName(verb);
    params->tenant           = tenant;
    params->servicePath      = spathList;
    params->xauthToken       = xauthToken;
    params->resource         = uriPath;
    params->content_type     = content_type;
    params->content          = payloadString;
    params->mimeType         = JSON;
    params->renderFormat     = renderFormatToString(renderFormat);
    params->fiwareCorrelator = fiwareCorrelator;

    // Cuidadito con esto
    strncpy(params->transactionId, transactionId, sizeof(params->transactionId));

    paramsV->push_back(params);
    return paramsV;

}

<|endoftext|>


<commit_before>/*
 * Copyright (C) 2019 The Android Open Source Project
 *
 * 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 <stdlib.h>
#include <sys/system_properties.h>
#include <sys/types.h>
#include <sys/wait.h>

#include "perfetto/base/logging.h"
#include "perfetto/tracing/core/data_source_config.h"
#include "src/base/test/test_task_runner.h"
#include "test/cts/utils.h"
#include "test/gtest_and_gmock.h"
#include "test/test_helper.h"

#include "protos/perfetto/config/profiling/java_hprof_config.gen.h"
#include "protos/perfetto/trace/profiling/heap_graph.gen.h"
#include "protos/perfetto/trace/profiling/profile_common.gen.h"
#include "protos/perfetto/trace/trace_packet.gen.h"

namespace perfetto {
namespace {

std::vector<protos::gen::TracePacket> ProfileRuntime(std::string app_name) {
  base::TestTaskRunner task_runner;

  // (re)start the target app's main activity
  if (IsAppRunning(app_name)) {
    StopApp(app_name, "old.app.stopped", &task_runner);
    task_runner.RunUntilCheckpoint("old.app.stopped", 1000 /*ms*/);
  }
  StartAppActivity(app_name, "MainActivity", "target.app.running", &task_runner,
                   /*delay_ms=*/100);
  task_runner.RunUntilCheckpoint("target.app.running", 1000 /*ms*/);
  // If we try to dump too early in app initialization, we sometimes deadlock.
  sleep(1);

  // set up tracing
  TestHelper helper(&task_runner);
  helper.ConnectConsumer();
  helper.WaitForConsumerConnect();

  TraceConfig trace_config;
  trace_config.add_buffers()->set_size_kb(20 * 1024);
  trace_config.set_duration_ms(6000);

  auto* ds_config = trace_config.add_data_sources()->mutable_config();
  ds_config->set_name("android.java_hprof");
  ds_config->set_target_buffer(0);

  protos::gen::JavaHprofConfig java_hprof_config;
  java_hprof_config.add_process_cmdline(app_name.c_str());
  ds_config->set_java_hprof_config_raw(java_hprof_config.SerializeAsString());

  // start tracing
  helper.StartTracing(trace_config);
  helper.WaitForTracingDisabled(10000 /*ms*/);
  helper.ReadData();
  helper.WaitForReadData();
  StopApp(app_name, "new.app.stopped", &task_runner);
  task_runner.RunUntilCheckpoint("new.app.stopped", 1000 /*ms*/);
  return helper.trace();
}

void AssertGraphPresent(std::vector<protos::gen::TracePacket> packets) {
  ASSERT_GT(packets.size(), 0u);

  size_t objects = 0;
  size_t roots = 0;
  for (const auto& packet : packets) {
    objects += static_cast<size_t>(packet.heap_graph().objects_size());
    roots += static_cast<size_t>(packet.heap_graph().roots_size());
  }
  ASSERT_GT(objects, 0u);
  ASSERT_GT(roots, 0u);
}

void AssertNoProfileContents(std::vector<protos::gen::TracePacket> packets) {
  // If profile packets are present, they must be empty.
  for (const auto& packet : packets) {
    ASSERT_EQ(packet.heap_graph().roots_size(), 0);
    ASSERT_EQ(packet.heap_graph().objects_size(), 0);
    ASSERT_EQ(packet.heap_graph().type_names_size(), 0);
    ASSERT_EQ(packet.heap_graph().field_names_size(), 0);
  }
}

TEST(HeapprofdJavaCtsTest, DebuggableAppRuntime) {
  std::string app_name = "android.perfetto.cts.app.debuggable";
  const auto& packets = ProfileRuntime(app_name);
  AssertGraphPresent(packets);
}

TEST(HeapprofdJavaCtsTest, ProfileableAppRuntime) {
  std::string app_name = "android.perfetto.cts.app.profileable";
  const auto& packets = ProfileRuntime(app_name);
  AssertGraphPresent(packets);
}

TEST(HeapprofdJavaCtsTest, ReleaseAppRuntime) {
  std::string app_name = "android.perfetto.cts.app.release";
  const auto& packets = ProfileRuntime(app_name);

  if (IsDebuggableBuild())
    AssertGraphPresent(packets);
  else
    AssertNoProfileContents(packets);
}

}  // namespace
}  // namespace perfetto
<commit_msg>Check if app is still running after test.<commit_after>/*
 * Copyright (C) 2019 The Android Open Source Project
 *
 * 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 <stdlib.h>
#include <sys/system_properties.h>
#include <sys/types.h>
#include <sys/wait.h>

#include "perfetto/base/logging.h"
#include "perfetto/tracing/core/data_source_config.h"
#include "src/base/test/test_task_runner.h"
#include "test/cts/utils.h"
#include "test/gtest_and_gmock.h"
#include "test/test_helper.h"

#include "protos/perfetto/config/profiling/java_hprof_config.gen.h"
#include "protos/perfetto/trace/profiling/heap_graph.gen.h"
#include "protos/perfetto/trace/profiling/profile_common.gen.h"
#include "protos/perfetto/trace/trace_packet.gen.h"

namespace perfetto {
namespace {

std::vector<protos::gen::TracePacket> ProfileRuntime(std::string app_name) {
  base::TestTaskRunner task_runner;

  // (re)start the target app's main activity
  if (IsAppRunning(app_name)) {
    StopApp(app_name, "old.app.stopped", &task_runner);
    task_runner.RunUntilCheckpoint("old.app.stopped", 1000 /*ms*/);
  }
  StartAppActivity(app_name, "MainActivity", "target.app.running", &task_runner,
                   /*delay_ms=*/100);
  task_runner.RunUntilCheckpoint("target.app.running", 1000 /*ms*/);
  // If we try to dump too early in app initialization, we sometimes deadlock.
  sleep(1);

  // set up tracing
  TestHelper helper(&task_runner);
  helper.ConnectConsumer();
  helper.WaitForConsumerConnect();

  TraceConfig trace_config;
  trace_config.add_buffers()->set_size_kb(20 * 1024);
  trace_config.set_duration_ms(6000);

  auto* ds_config = trace_config.add_data_sources()->mutable_config();
  ds_config->set_name("android.java_hprof");
  ds_config->set_target_buffer(0);

  protos::gen::JavaHprofConfig java_hprof_config;
  java_hprof_config.add_process_cmdline(app_name.c_str());
  ds_config->set_java_hprof_config_raw(java_hprof_config.SerializeAsString());

  // start tracing
  helper.StartTracing(trace_config);
  helper.WaitForTracingDisabled(10000 /*ms*/);
  helper.ReadData();
  helper.WaitForReadData();
  PERFETTO_CHECK(IsAppRunning(app_name));
  StopApp(app_name, "new.app.stopped", &task_runner);
  task_runner.RunUntilCheckpoint("new.app.stopped", 1000 /*ms*/);
  return helper.trace();
}

void AssertGraphPresent(std::vector<protos::gen::TracePacket> packets) {
  ASSERT_GT(packets.size(), 0u);

  size_t objects = 0;
  size_t roots = 0;
  for (const auto& packet : packets) {
    objects += static_cast<size_t>(packet.heap_graph().objects_size());
    roots += static_cast<size_t>(packet.heap_graph().roots_size());
  }
  ASSERT_GT(objects, 0u);
  ASSERT_GT(roots, 0u);
}

void AssertNoProfileContents(std::vector<protos::gen::TracePacket> packets) {
  // If profile packets are present, they must be empty.
  for (const auto& packet : packets) {
    ASSERT_EQ(packet.heap_graph().roots_size(), 0);
    ASSERT_EQ(packet.heap_graph().objects_size(), 0);
    ASSERT_EQ(packet.heap_graph().type_names_size(), 0);
    ASSERT_EQ(packet.heap_graph().field_names_size(), 0);
  }
}

TEST(HeapprofdJavaCtsTest, DebuggableAppRuntime) {
  std::string app_name = "android.perfetto.cts.app.debuggable";
  const auto& packets = ProfileRuntime(app_name);
  AssertGraphPresent(packets);
}

TEST(HeapprofdJavaCtsTest, ProfileableAppRuntime) {
  std::string app_name = "android.perfetto.cts.app.profileable";
  const auto& packets = ProfileRuntime(app_name);
  AssertGraphPresent(packets);
}

TEST(HeapprofdJavaCtsTest, ReleaseAppRuntime) {
  std::string app_name = "android.perfetto.cts.app.release";
  const auto& packets = ProfileRuntime(app_name);

  if (IsDebuggableBuild())
    AssertGraphPresent(packets);
  else
    AssertNoProfileContents(packets);
}

}  // namespace
}  // namespace perfetto
<|endoftext|>


<commit_before>#include <sstream>

#define CATCH_CONFIG_MAIN
#include <catch2/catch.hpp>

#include "Advice.hpp"
#include "Point.hpp"

bool checkInput(const size_t &pathCount, const std::string &pathes, const Point &expectedAverage,
                const double &expectedLongestDistance) {
  std::stringstream ss;
  ss << pathes;
  AdviceCalculator calculator{pathCount};
  calculator.readDatas(ss);
  auto pointAverage = calculator.getAverageDestination();
  CHECK(pointAverage.x == Approx(expectedAverage.x));
  CHECK(pointAverage.y == Approx(expectedAverage.y));
  CHECK(calculator.getLongestDistance() == Approx(expectedLongestDistance));
  return false;
};

TEST_CASE("Simple route") {
  constexpr auto pathCount = 1u;
  const auto pathes = "87.342 34.30 start 0 walk 10.0\n";
  constexpr Point expectedAverage{97.342, 34.30};
  constexpr auto expectedLongestDistance = 0.0;
  REQUIRE_NOTHROW(checkInput(pathCount, pathes, expectedAverage, expectedLongestDistance));
};

TEST_CASE("Long route") {
  constexpr auto pathCount = 1u;
  const auto pathes =
      "87.342 34.30 start 0 walk 10.0 walk 40 turn 40.0 walk 60  walk 50 turn 90 walk 40 turn 13 walk 5\n";
  constexpr Point expectedAverage{191.9022, 138.6574};
  constexpr auto expectedLongestDistance = 0.0;
  REQUIRE_NOTHROW(checkInput(pathCount, pathes, expectedAverage, expectedLongestDistance));
};

TEST_CASE("Two routes") {
  constexpr auto pathCount = 2u;
  const auto pathes = "30 40 start 90 walk 5\n"
                      "40 50 start 180 walk 10 turn 90 walk 5\n";
  constexpr Point expectedAverage{30, 45};
  constexpr auto expectedLongestDistance = 0;
  REQUIRE_NOTHROW(checkInput(pathCount, pathes, expectedAverage, expectedLongestDistance));
};

TEST_CASE("Three routes") {
  constexpr auto pathCount = 3u;
  const auto pathes = "87.342 34.30 start 0 walk 10.0\n"
                      "2.6762 75.2811 start -45.0 walk 40 turn 40.0 walk 60\n"
                      "58.518 93.508 start 270 walk 50 turn 90 walk 40 turn 13 walk 5\n";
  constexpr Point expectedAverage{97.1547, 40.2334};
  constexpr auto expectedLongestDistance = 7.63097;
  REQUIRE_NOTHROW(checkInput(pathCount, pathes, expectedAverage, expectedLongestDistance));
};<commit_msg>Remove unnecessary semicolons<commit_after>#include <sstream>

#define CATCH_CONFIG_MAIN
#include <catch2/catch.hpp>

#include "Advice.hpp"
#include "Point.hpp"

bool checkInput(const size_t &pathCount, const std::string &pathes, const Point &expectedAverage,
                const double &expectedLongestDistance) {
  std::stringstream ss;
  ss << pathes;
  AdviceCalculator calculator{pathCount};
  calculator.readDatas(ss);
  auto pointAverage = calculator.getAverageDestination();
  CHECK(pointAverage.x == Approx(expectedAverage.x));
  CHECK(pointAverage.y == Approx(expectedAverage.y));
  CHECK(calculator.getLongestDistance() == Approx(expectedLongestDistance));
  return false;
}

TEST_CASE("Simple route") {
  constexpr auto pathCount = 1u;
  const auto pathes = "87.342 34.30 start 0 walk 10.0\n";
  constexpr Point expectedAverage{97.342, 34.30};
  constexpr auto expectedLongestDistance = 0.0;
  REQUIRE_NOTHROW(checkInput(pathCount, pathes, expectedAverage, expectedLongestDistance));
}

TEST_CASE("Long route") {
  constexpr auto pathCount = 1u;
  const auto pathes =
      "87.342 34.30 start 0 walk 10.0 walk 40 turn 40.0 walk 60  walk 50 turn 90 walk 40 turn 13 walk 5\n";
  constexpr Point expectedAverage{191.9022, 138.6574};
  constexpr auto expectedLongestDistance = 0.0;
  REQUIRE_NOTHROW(checkInput(pathCount, pathes, expectedAverage, expectedLongestDistance));
}

TEST_CASE("Two routes") {
  constexpr auto pathCount = 2u;
  const auto pathes = "30 40 start 90 walk 5\n"
                      "40 50 start 180 walk 10 turn 90 walk 5\n";
  constexpr Point expectedAverage{30, 45};
  constexpr auto expectedLongestDistance = 0;
  REQUIRE_NOTHROW(checkInput(pathCount, pathes, expectedAverage, expectedLongestDistance));
}

TEST_CASE("Three routes") {
  constexpr auto pathCount = 3u;
  const auto pathes = "87.342 34.30 start 0 walk 10.0\n"
                      "2.6762 75.2811 start -45.0 walk 40 turn 40.0 walk 60\n"
                      "58.518 93.508 start 270 walk 50 turn 90 walk 40 turn 13 walk 5\n";
  constexpr Point expectedAverage{97.1547, 40.2334};
  constexpr auto expectedLongestDistance = 7.63097;
  REQUIRE_NOTHROW(checkInput(pathCount, pathes, expectedAverage, expectedLongestDistance));
}<|endoftext|>


<commit_before>/**
 * Simple Image Processing Library
 * Copyright Erik Smistad 2012
 * See LICENSE file for information on use
 */
#include "Core.hpp"
#include "Visualization.hpp"
#include <limits>

namespace SIPL {
bool init = false;
GThread * gtkThread;
int windowCount;
GMutex * windowCountMutex;
void * initGTK(void * t) {
	gdk_threads_init ();
	gtk_init(0, (char ***) "");
	init = true;
    windowCountMutex = g_mutex_new();
	gdk_threads_enter ();
	gtk_main();
    gdk_threads_leave();
    return 0;
}

void Quit() {
    gtk_main_quit();
	g_thread_join(gtkThread);
    exit(0);
}

bool isInit() {
    return init;
}

void saveImage(BaseDataset * d, const char * filepath, const char * imageType) {
    Visualization * v = new Visualization(d);
    GdkPixbuf * pixBuf = v->render();
    delete v;
	gdk_pixbuf_save(pixBuf, filepath, imageType, NULL, NULL);
}

Visualization * displayVisualization(BaseDataset * d, float level, float window) {
    Visualization * v = new Visualization(d);
    v->setLevel(level);
    v->setWindow(window);
    v->display();
    return v;
}

Visualization * displayVolumeVisualization(BaseDataset * d, int slice, slice_plane direction, float level, float window) {
    Visualization * v = new Visualization(d);
    v->setLevel(level);
    v->setWindow(window);
    v->setSlice(slice);
    v->setDirection(direction);
    v->display();
    return v;
}

Visualization * displayMIPVisualization(BaseDataset * d, slice_plane direction, float level, float window) {
    Visualization * v = new Visualization(d);
    v->setType(MIP);
    v->setLevel(level);
    v->setWindow(window);
    v->setDirection(direction);
    v->display();
    return v;
}

int validateSlice(int slice, slice_plane direction, int3 size) {
    if(slice < 0)
        return 0;

    switch(direction) {
        case X:
            if(slice > size.x-1)
                return size.x-1;
            break;
        case Y:
            if(slice > size.y-1)
                return size.y-1;
            break;
        case Z:
            if(slice > size.z-1)
                return size.z-1;
            break;
    }
    return slice;
}
int getWindowCount() {
    g_mutex_lock(windowCountMutex);
    int wc = windowCount;
    g_mutex_unlock(windowCountMutex);
    return wc;
}
int increaseWindowCount() {
    g_mutex_lock(windowCountMutex);
    windowCount++;
    int wc = windowCount;
    g_mutex_unlock(windowCountMutex);
    return wc;
}
int decreaseWindowCount() {
    g_mutex_lock(windowCountMutex);
    windowCount--;
    int wc = windowCount;
    g_mutex_unlock(windowCountMutex);
    return wc;
}
bool endReached = false;
void quit(void) {
    endReached = true;
    if(getWindowCount() == 0)
        gtk_main_quit();
	g_thread_join(gtkThread);
}

void Init() {
    windowCount = 0;
	if (!init) {
		gtkThread = g_thread_new("main", initGTK, NULL);
	}
	while(!init); // wait for the thread to be created
    atexit(quit);
}

void destroyWindow(GtkWidget * widget, gpointer window) {
	if (decreaseWindowCount() == 0 && endReached) {
		gtk_main_quit();
	}
}

void quitProgram(GtkWidget * widget, gpointer window) {
    gtk_main_quit();
    exit(0);
}

void signalDestroyWindow(GtkWidget * widget, gpointer window) {
	if (decreaseWindowCount() == 0 && endReached) {
        gtk_main_quit();
	} else {
        gtk_widget_hide(GTK_WIDGET(window));
    }
}

void saveFileSignal(GtkWidget * widget, gpointer data) {
	// Get extension to determine image type
    std::string filepath(gtk_file_selection_get_filename (GTK_FILE_SELECTION (((_saveData *)data)->fs)));
	gdk_pixbuf_save(gtk_image_get_pixbuf(
			((_saveData *)data)->image),
			filepath.c_str(),
			filepath.substr(filepath.rfind('.')+1).c_str(),
			NULL, "quality", "100", NULL);

	gtk_widget_destroy(GTK_WIDGET(((_saveData *)data)->fs));
}

void refresh(GtkWidget * widget, gpointer data) {
    Visualization * v = (Visualization *)data;
    v->update();
}

char * floatToChar(float v) {
	char * str = new char[10];
	sprintf(str, "%f", v);
	return str;
}

void getMinAndMax(BaseDataset * image, float * min, float * max) {
    *min = std::numeric_limits<float>::max();
    *max = std::numeric_limits<float>::min();
    if(image->isVectorType) {
        float3 * floatData = image->getVectorFloatData();
        for(int i = 0; i < image->getTotalSize(); i++) {
            *min = std::min(*min, std::min(floatData[i].x, std::min(floatData[i].y, floatData[i].z)));
            *max = std::max(*max, std::max(floatData[i].x, std::max(floatData[i].y, floatData[i].z)));
        }

        delete[] floatData;
    } else {
        float * floatData = image->getFloatData();
        for(int i = 0; i < image->getTotalSize(); i++) {
            if(floatData[i] < *min)
                *min = floatData[i];
            if(floatData[i] > *max)
                *max = floatData[i];
        }
        delete[] floatData;
    }
}

struct levelWindowChange {
        Visualization * viz;
        BaseDataset * image;
        GtkWidget * otherWidget;
};

void entryChangeLevel(GtkWidget * widget, gpointer data) {
    Visualization * v = (Visualization *)data;
    const gchar * value = gtk_entry_get_text(GTK_ENTRY(widget));
    v->setLevel(atof((char*)value));
    v->update();
}

void scaleChangeLevel(GtkWidget * widget, gpointer data) {
    Visualization * v = (Visualization *)data;
    gdouble value = gtk_range_get_value(GTK_RANGE(widget));
    v->setLevel((float)value);
    v->update();
}

void entryChangeWindow(GtkWidget * widget, gpointer data) {
    Visualization * v = (Visualization *)data;
    const gchar * value = gtk_entry_get_text(GTK_ENTRY(widget));
    v->setWindow(atof((char*)value));
    v->update();
}

void scaleChangeWindow(GtkWidget * widget, gpointer data) {
    Visualization * v = (Visualization *)data;
    gdouble value = gtk_range_get_value(GTK_RANGE(widget));
    v->setWindow((float)value);
    v->update();
}

void adjustLevelAndWindow(GtkWidget * widget, gpointer data) {
    Visualization * v = (Visualization *)data;
    // Create window and add sliders and text boxes to it, one for each image
    GtkWidget * window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
    gtk_window_set_title(GTK_WINDOW(window), "Adjust Level & Window");
	gtk_window_set_position(GTK_WINDOW(window), GTK_WIN_POS_CENTER);

    GtkWidget * vbox = gtk_vbox_new(FALSE, 1);
	gtk_container_add (GTK_CONTAINER (window), vbox);

	// TODO: retrieve min and max of image and the current level
	std::vector<BaseDataset *> images = v->getImages();

	for(int i = 0; i < images.size(); i++) {
        float currentLevel = v->getLevel(images[i]);
        float min,max;
        getMinAndMax(images[i], &min, &max);

        GtkWidget * levelLabel = gtk_label_new("Level: ");
        gtk_container_add(GTK_CONTAINER(vbox), levelLabel);
        GtkWidget * levelScale = gtk_hscale_new_with_range(min, max, (max-min)/255.0f);
        gtk_range_set_value(GTK_RANGE(levelScale), currentLevel);
        g_signal_connect(
                levelScale, "value-changed",
                G_CALLBACK(scaleChangeLevel),
                v);
        gtk_container_add(GTK_CONTAINER(vbox), levelScale);
        GtkWidget * levelEntry = gtk_entry_new();
        gtk_entry_set_text(GTK_ENTRY(levelEntry), floatToChar(currentLevel));
        g_signal_connect(
                levelEntry, "activate",
                G_CALLBACK(entryChangeLevel),
                v);
        gtk_container_add(GTK_CONTAINER(vbox), levelEntry);

        float currentWindow = v->getWindow(images[i]);

        GtkWidget * windowLabel = gtk_label_new("Window: ");
        gtk_container_add(GTK_CONTAINER(vbox), windowLabel);
        GtkWidget * windowScale = gtk_hscale_new_with_range(0, max, (max)/255.0f);
        gtk_range_set_value(GTK_RANGE(windowScale), currentWindow);
        g_signal_connect(
                windowScale, "value-changed",
                G_CALLBACK(scaleChangeWindow),
                v);
        gtk_container_add(GTK_CONTAINER(vbox), windowScale);
        GtkWidget * windowEntry = gtk_entry_new();
        gtk_entry_set_text(GTK_ENTRY(windowEntry), floatToChar(currentWindow));
        g_signal_connect(
                windowEntry, "activate",
                G_CALLBACK(entryChangeWindow),
                v);
        gtk_container_add(GTK_CONTAINER(vbox), windowEntry);
	}

    gtk_widget_show_all(window);
}

void saveDialog(GtkWidget * widget, gpointer image) {
	GtkWidget * fileSelection = gtk_file_selection_new("Save an image");

	_saveData * data = (_saveData *)malloc(sizeof(_saveData));
	data->fs = fileSelection;
	data->image = (GtkImage *)image;

	/* Connect the ok_button to file_ok_sel function */
	g_signal_connect (G_OBJECT (GTK_FILE_SELECTION (fileSelection)->ok_button),
			      "clicked", G_CALLBACK (saveFileSignal), data);

	/* Connect the cancel_button to destroy the widget */
	g_signal_connect_swapped (G_OBJECT (GTK_FILE_SELECTION (fileSelection)->cancel_button),
		                      "clicked", G_CALLBACK (gtk_widget_destroy),
				      G_OBJECT (fileSelection));

	gtk_widget_show(fileSelection);
}

uchar color2gray(uchar * p) {
   return 0.33*(p[0]+p[1]+p[2]);
}

void toT(bool * r, uchar * p) {
    *r = color2gray(p) > 128;
}
void toT(uchar * r, uchar * p) {
    *r = color2gray(p);
}
void toT(char * r, uchar * p) {
    *r = color2gray(p)-128;
}
void toT(ushort * r, uchar * p) {
    *r = ((float)color2gray(p)/255.0f)*65535;
}
void toT(short * r, uchar * p) {
    *r = (((float)color2gray(p)/255.0f)-0.5f)*65535;
}
void toT(uint * r, uchar * p) {
    *r = (((float)color2gray(p)/255.0f))*4294967295;
}
void toT(int * r, uchar * p) {
    *r = (((float)color2gray(p)/255.0f)-0.5f)*4294967295;
}
void toT(float * r, uchar * p) {
    *r = (float)color2gray(p)/255.0f;
}
void toT(color_uchar * c, uchar * p) {
    c->red = p[0];
    c->green = p[1];
    c->blue = p[2];
}
void toT(color_float * c, uchar * p) {
    c->red = (float)p[0]/255.0f;
    c->green = (float)p[1]/255.0f;
    c->blue = (float)p[2]/255.0f;
}
void toT(float2 * c, uchar * p) {
    c->x = (float)p[0]/255.0f;
    c->y = (float)p[1]/255.0f;
}
void toT(float3 * c, uchar * p) {
    c->x = (float)p[0]/255.0f;
    c->y = (float)p[1]/255.0f;
    c->z = (float)p[2]/255.0f;
}
template <>
void Dataset<color_uchar>::setDefaultLevelWindow() {
    this->defaultLevel = 255*0.5;
    this->defaultWindow = 255;
}
template <>
void Dataset<uchar>::setDefaultLevelWindow() {
    this->defaultLevel = 255*0.5;
    this->defaultWindow = 255;
}
template <>
void Dataset<char>::setDefaultLevelWindow() {
    this->defaultLevel = 0;
    this->defaultWindow = 255;
}
} // End namespace
<commit_msg>changing level and window updates all widgets<commit_after>/**
 * Simple Image Processing Library
 * Copyright Erik Smistad 2012
 * See LICENSE file for information on use
 */
#include "Core.hpp"
#include "Visualization.hpp"
#include <limits>

namespace SIPL {
bool init = false;
GThread * gtkThread;
int windowCount;
GMutex * windowCountMutex;
void * initGTK(void * t) {
	gdk_threads_init ();
	gtk_init(0, (char ***) "");
	init = true;
    windowCountMutex = g_mutex_new();
	gdk_threads_enter ();
	gtk_main();
    gdk_threads_leave();
    return 0;
}

void Quit() {
    gtk_main_quit();
	g_thread_join(gtkThread);
    exit(0);
}

bool isInit() {
    return init;
}

void saveImage(BaseDataset * d, const char * filepath, const char * imageType) {
    Visualization * v = new Visualization(d);
    GdkPixbuf * pixBuf = v->render();
    delete v;
	gdk_pixbuf_save(pixBuf, filepath, imageType, NULL, NULL);
}

Visualization * displayVisualization(BaseDataset * d, float level, float window) {
    Visualization * v = new Visualization(d);
    v->setLevel(level);
    v->setWindow(window);
    v->display();
    return v;
}

Visualization * displayVolumeVisualization(BaseDataset * d, int slice, slice_plane direction, float level, float window) {
    Visualization * v = new Visualization(d);
    v->setLevel(level);
    v->setWindow(window);
    v->setSlice(slice);
    v->setDirection(direction);
    v->display();
    return v;
}

Visualization * displayMIPVisualization(BaseDataset * d, slice_plane direction, float level, float window) {
    Visualization * v = new Visualization(d);
    v->setType(MIP);
    v->setLevel(level);
    v->setWindow(window);
    v->setDirection(direction);
    v->display();
    return v;
}

int validateSlice(int slice, slice_plane direction, int3 size) {
    if(slice < 0)
        return 0;

    switch(direction) {
        case X:
            if(slice > size.x-1)
                return size.x-1;
            break;
        case Y:
            if(slice > size.y-1)
                return size.y-1;
            break;
        case Z:
            if(slice > size.z-1)
                return size.z-1;
            break;
    }
    return slice;
}
int getWindowCount() {
    g_mutex_lock(windowCountMutex);
    int wc = windowCount;
    g_mutex_unlock(windowCountMutex);
    return wc;
}
int increaseWindowCount() {
    g_mutex_lock(windowCountMutex);
    windowCount++;
    int wc = windowCount;
    g_mutex_unlock(windowCountMutex);
    return wc;
}
int decreaseWindowCount() {
    g_mutex_lock(windowCountMutex);
    windowCount--;
    int wc = windowCount;
    g_mutex_unlock(windowCountMutex);
    return wc;
}
bool endReached = false;
void quit(void) {
    endReached = true;
    if(getWindowCount() == 0)
        gtk_main_quit();
	g_thread_join(gtkThread);
}

void Init() {
    windowCount = 0;
	if (!init) {
		gtkThread = g_thread_new("main", initGTK, NULL);
	}
	while(!init); // wait for the thread to be created
    atexit(quit);
}

void destroyWindow(GtkWidget * widget, gpointer window) {
	if (decreaseWindowCount() == 0 && endReached) {
		gtk_main_quit();
	}
}

void quitProgram(GtkWidget * widget, gpointer window) {
    gtk_main_quit();
    exit(0);
}

void signalDestroyWindow(GtkWidget * widget, gpointer window) {
	if (decreaseWindowCount() == 0 && endReached) {
        gtk_main_quit();
	} else {
        gtk_widget_hide(GTK_WIDGET(window));
    }
}

void saveFileSignal(GtkWidget * widget, gpointer data) {
	// Get extension to determine image type
    std::string filepath(gtk_file_selection_get_filename (GTK_FILE_SELECTION (((_saveData *)data)->fs)));
	gdk_pixbuf_save(gtk_image_get_pixbuf(
			((_saveData *)data)->image),
			filepath.c_str(),
			filepath.substr(filepath.rfind('.')+1).c_str(),
			NULL, "quality", "100", NULL);

	gtk_widget_destroy(GTK_WIDGET(((_saveData *)data)->fs));
}

void refresh(GtkWidget * widget, gpointer data) {
    Visualization * v = (Visualization *)data;
    v->update();
}

char * floatToChar(float v) {
	char * str = new char[10];
	sprintf(str, "%f", v);
	return str;
}

void getMinAndMax(BaseDataset * image, float * min, float * max) {
    *min = std::numeric_limits<float>::max();
    *max = std::numeric_limits<float>::min();
    if(image->isVectorType) {
        float3 * floatData = image->getVectorFloatData();
        for(int i = 0; i < image->getTotalSize(); i++) {
            *min = std::min(*min, std::min(floatData[i].x, std::min(floatData[i].y, floatData[i].z)));
            *max = std::max(*max, std::max(floatData[i].x, std::max(floatData[i].y, floatData[i].z)));
        }

        delete[] floatData;
    } else {
        float * floatData = image->getFloatData();
        for(int i = 0; i < image->getTotalSize(); i++) {
            if(floatData[i] < *min)
                *min = floatData[i];
            if(floatData[i] > *max)
                *max = floatData[i];
        }
        delete[] floatData;
    }
}

class LevelWindowChange {
    public:
        LevelWindowChange(Visualization * v, BaseDataset * i, GtkWidget * w) {
            viz = v;
            image = i;
            otherWidget = w;
        };
        Visualization * viz;
        BaseDataset * image;
        GtkWidget * otherWidget;
};

void entryChangeLevel(GtkWidget * widget, gpointer data) {
    LevelWindowChange * c = (LevelWindowChange *)data;
    const gchar * value = gtk_entry_get_text(GTK_ENTRY(widget));
    gtk_range_set_value(GTK_RANGE(c->otherWidget), atof((char*)value));
    c->viz->setLevel(c->image,atof((char*)value));
    c->viz->update();
}

void scaleChangeLevel(GtkWidget * widget, gpointer data) {
    LevelWindowChange * c = (LevelWindowChange *)data;
    gdouble value = gtk_range_get_value(GTK_RANGE(widget));
    gtk_entry_set_text(GTK_ENTRY(c->otherWidget), floatToChar((float)value));
    c->viz->setLevel(c->image, (float)value);
    c->viz->update();
}

void entryChangeWindow(GtkWidget * widget, gpointer data) {
    LevelWindowChange * c = (LevelWindowChange *)data;
    const gchar * value = gtk_entry_get_text(GTK_ENTRY(widget));
    gtk_range_set_value(GTK_RANGE(c->otherWidget), atof((char*)value));
    c->viz->setWindow(c->image,atof((char*)value));
    c->viz->update();
}

void scaleChangeWindow(GtkWidget * widget, gpointer data) {
    LevelWindowChange * c = (LevelWindowChange *)data;
    gdouble value = gtk_range_get_value(GTK_RANGE(widget));
    gtk_entry_set_text(GTK_ENTRY(c->otherWidget), floatToChar((float)value));
    c->viz->setWindow(c->image, (float)value);
    c->viz->update();
}

void adjustLevelAndWindow(GtkWidget * widget, gpointer data) {
    Visualization * v = (Visualization *)data;
    // Create window and add sliders and text boxes to it, one for each image
    GtkWidget * window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
    gtk_window_set_title(GTK_WINDOW(window), "Adjust Level & Window");
	gtk_window_set_position(GTK_WINDOW(window), GTK_WIN_POS_CENTER);

    GtkWidget * vbox = gtk_vbox_new(FALSE, 1);
	gtk_container_add (GTK_CONTAINER (window), vbox);

	// TODO: retrieve min and max of image and the current level
	std::vector<BaseDataset *> images = v->getImages();

	for(int i = 0; i < images.size(); i++) {
        float currentLevel = v->getLevel(images[i]);
        float min,max;
        getMinAndMax(images[i], &min, &max);

        GtkWidget * levelLabel = gtk_label_new("Level: ");
        gtk_container_add(GTK_CONTAINER(vbox), levelLabel);
        GtkWidget * levelScale = gtk_hscale_new_with_range(min, max, (max-min)/255.0f);
        gtk_range_set_value(GTK_RANGE(levelScale), currentLevel);
        gtk_container_add(GTK_CONTAINER(vbox), levelScale);
        GtkWidget * levelEntry = gtk_entry_new();
        gtk_entry_set_text(GTK_ENTRY(levelEntry), floatToChar(currentLevel));
        g_signal_connect(
                levelScale, "value-changed",
                G_CALLBACK(scaleChangeLevel),
                new LevelWindowChange(v,images[i],levelEntry));
        g_signal_connect(
                levelEntry, "activate",
                G_CALLBACK(entryChangeLevel),
                new LevelWindowChange(v, images[i], levelScale));
        gtk_container_add(GTK_CONTAINER(vbox), levelEntry);

        float currentWindow = v->getWindow(images[i]);

        GtkWidget * windowLabel = gtk_label_new("Window: ");
        gtk_container_add(GTK_CONTAINER(vbox), windowLabel);
        GtkWidget * windowScale = gtk_hscale_new_with_range(0, max, (max)/255.0f);
        gtk_range_set_value(GTK_RANGE(windowScale), currentWindow);
        gtk_container_add(GTK_CONTAINER(vbox), windowScale);
        GtkWidget * windowEntry = gtk_entry_new();
        gtk_entry_set_text(GTK_ENTRY(windowEntry), floatToChar(currentWindow));
        g_signal_connect(
                windowScale, "value-changed",
                G_CALLBACK(scaleChangeLevel),
                new LevelWindowChange(v,images[i],windowEntry));
        g_signal_connect(
                windowEntry, "activate",
                G_CALLBACK(entryChangeLevel),
                new LevelWindowChange(v, images[i], windowScale));
        gtk_container_add(GTK_CONTAINER(vbox), windowEntry);
	}

    gtk_widget_show_all(window);
}

void saveDialog(GtkWidget * widget, gpointer image) {
	GtkWidget * fileSelection = gtk_file_selection_new("Save an image");

	_saveData * data = (_saveData *)malloc(sizeof(_saveData));
	data->fs = fileSelection;
	data->image = (GtkImage *)image;

	/* Connect the ok_button to file_ok_sel function */
	g_signal_connect (G_OBJECT (GTK_FILE_SELECTION (fileSelection)->ok_button),
			      "clicked", G_CALLBACK (saveFileSignal), data);

	/* Connect the cancel_button to destroy the widget */
	g_signal_connect_swapped (G_OBJECT (GTK_FILE_SELECTION (fileSelection)->cancel_button),
		                      "clicked", G_CALLBACK (gtk_widget_destroy),
				      G_OBJECT (fileSelection));

	gtk_widget_show(fileSelection);
}

uchar color2gray(uchar * p) {
   return 0.33*(p[0]+p[1]+p[2]);
}

void toT(bool * r, uchar * p) {
    *r = color2gray(p) > 128;
}
void toT(uchar * r, uchar * p) {
    *r = color2gray(p);
}
void toT(char * r, uchar * p) {
    *r = color2gray(p)-128;
}
void toT(ushort * r, uchar * p) {
    *r = ((float)color2gray(p)/255.0f)*65535;
}
void toT(short * r, uchar * p) {
    *r = (((float)color2gray(p)/255.0f)-0.5f)*65535;
}
void toT(uint * r, uchar * p) {
    *r = (((float)color2gray(p)/255.0f))*4294967295;
}
void toT(int * r, uchar * p) {
    *r = (((float)color2gray(p)/255.0f)-0.5f)*4294967295;
}
void toT(float * r, uchar * p) {
    *r = (float)color2gray(p)/255.0f;
}
void toT(color_uchar * c, uchar * p) {
    c->red = p[0];
    c->green = p[1];
    c->blue = p[2];
}
void toT(color_float * c, uchar * p) {
    c->red = (float)p[0]/255.0f;
    c->green = (float)p[1]/255.0f;
    c->blue = (float)p[2]/255.0f;
}
void toT(float2 * c, uchar * p) {
    c->x = (float)p[0]/255.0f;
    c->y = (float)p[1]/255.0f;
}
void toT(float3 * c, uchar * p) {
    c->x = (float)p[0]/255.0f;
    c->y = (float)p[1]/255.0f;
    c->z = (float)p[2]/255.0f;
}
template <>
void Dataset<color_uchar>::setDefaultLevelWindow() {
    this->defaultLevel = 255*0.5;
    this->defaultWindow = 255;
}
template <>
void Dataset<uchar>::setDefaultLevelWindow() {
    this->defaultLevel = 255*0.5;
    this->defaultWindow = 255;
}
template <>
void Dataset<char>::setDefaultLevelWindow() {
    this->defaultLevel = 0;
    this->defaultWindow = 255;
}
} // End namespace
<|endoftext|>


<commit_before>/*
 * GaborConn.cpp
 *
 *  Created on: Jan 12, 2009
 *      Author: rasmussn
 */

#include "GaborConn.hpp"
#include "../io/io.h"
#include <assert.h>
#include <string.h>

namespace PV {

GaborConn::GaborConn(const char * name,
                     HyPerCol * hc, HyPerLayer * pre, HyPerLayer * post, int channel)
{
   this->connId = hc->numberOfConnections();
   this->name = strdup(name);
   this->parent = hc;
   this->numBundles = 1;

   initialize(NULL, pre, post, channel);

   hc->addConnection(this);
}

int GaborConn::initializeWeights(const char * filename)
{
   char outfile[64];

   float aspect = 4.0;
   float sigma  = 2.0;
   float rMax   = 8.0;
   float lambda = sigma/0.8;    // gabor wavelength
   float strength = 1.0;

   PVParams * params = parent->parameters();

   aspect = params->value(name, "aspect");
   sigma  = params->value(name, "sigma");
   rMax   = params->value(name, "rMax");
   lambda = params->value(name, "lambda");

   if (params->present(name, "strength")) {
      strength = params->value(name, "strength");
   }

   float r2Max = rMax * rMax;

   const int numPatches = numberOfWeightPatches();
   for (int i = 0; i < numPatches; i++) {
      int xScale = post->clayer->xScale - pre->clayer->xScale;
      int yScale = post->clayer->xScale - pre->clayer->yScale;
      gaborWeights(wPatches[i], xScale, yScale, aspect, sigma, r2Max, lambda, strength);
   }

   return 0;
}

int GaborConn::gaborWeights(PVPatch * wp, int xScale, int yScale,
                            float aspect, float sigma, float r2Max, float lambda, float strength)
{
   PVParams * params = parent->parameters();

   float rotate = 1.0;
   float invert = 0.0;
   if (params->present(name, "rotate")) rotate = params->value(name, "rotate");
   if (params->present(name, "invert")) invert = params->value(name, "invert");

   pvdata_t * w = wp->data;

   const float phi = 0.0;  // phase

   const int nx = (int) wp->nx;
   const int ny = (int) wp->ny;
   const int nf = (int) wp->nf;

   const int sx = (int) wp->sx;  assert(sx == nf);
   const int sy = (int) wp->sy;  assert(sy == nf*nx);
   const int sf = (int) wp->sf;  assert(sf == 1);

   const float dx = powf(2, xScale);
   const float dy = powf(2, yScale);

   // pre-synaptic neuron is at the center of the patch (0,0)
   // (x0,y0) is at upper left corner of patch (i=0,j=0)
   const float x0 = -(nx/2.0 - 0.5) * dx;
   const float y0 = +(ny/2.0 - 0.5) * dy;

   const float dth = PI/nf;
   const float th0 = -PI/2.0 + rotate*dth/2.0;

   for (int f = 0; f < nf; f++) {
      float th = th0 + f * dth;
      for (int j = 0; j < ny; j++) {
         float yp = y0 - j * dy;    // pixel coordinate
         for (int i = 0; i < nx; i++) {
            float xp  = x0 + i*dx;  // pixel coordinate

            // rotate the reference frame by th ((x,y) is center of patch (0,0))
            float u1 = + (0.0 - xp) * cos(th) + (0.0 - yp) * sin(th);
            float u2 = - (0.0 - xp) * sin(th) + (0.0 - yp) * cos(th);

            float factor = cos(2.0*PI*u2/lambda + phi);
            if (fabs(u2/lambda) > 3.0/4.0) factor = 0.0;  // phase < 3*PI/2 (no second positive band)
            float d2 = u1 * u1 + (aspect*u2 * aspect*u2);
            float wt = factor * expf(-d2 / (2.0*sigma*sigma));

#ifdef DEBUG_OUTPUT
            if (j == 0) printf("x=%f fac=%f w=%f\n", xp, factor, wt);
#endif
            if (xp*xp + yp*yp > r2Max) {
               w[i*sx + j*sy + f*sf] = 0.0;
            }
            else {
               if (invert) wt *= -1.0;
               if (wt < 0.0) wt = 0.0;       // clip negative values
               w[i*sx + j*sy + f*sf] = wt;
            }
         }
      }
   }

   // normalize
   for (int f = 0; f < nf; f++) {
      float sum = 0;
      for (int i = 0; i < nx*ny; i++) {
         if (w[f + i*nf] > 0.0) sum += w[f + i*nf];
      }

      if (sum == 0.0) continue;  // all weights == zero is ok

      float factor = strength/sum;
      for (int i = 0; i < nx*ny; i++) w[f + i*nf] *= factor;
   }

   return 0;
}

} // Namespace PV
<commit_msg>Moved 0 orientation starting from x axis.<commit_after>/*
 * GaborConn.cpp
 *
 *  Created on: Jan 12, 2009
 *      Author: rasmussn
 */

#include "GaborConn.hpp"
#include "../io/io.h"
#include <assert.h>
#include <string.h>

namespace PV {

GaborConn::GaborConn(const char * name,
                     HyPerCol * hc, HyPerLayer * pre, HyPerLayer * post, int channel)
{
   this->connId = hc->numberOfConnections();
   this->name = strdup(name);
   this->parent = hc;
   this->numBundles = 1;

   initialize(NULL, pre, post, channel);

   hc->addConnection(this);
}

int GaborConn::initializeWeights(const char * filename)
{
   char outfile[64];

   float aspect = 4.0;
   float sigma  = 2.0;
   float rMax   = 8.0;
   float lambda = sigma/0.8;    // gabor wavelength
   float strength = 1.0;

   PVParams * params = parent->parameters();

   aspect = params->value(name, "aspect");
   sigma  = params->value(name, "sigma");
   rMax   = params->value(name, "rMax");
   lambda = params->value(name, "lambda");

   if (params->present(name, "strength")) {
      strength = params->value(name, "strength");
   }

   float r2Max = rMax * rMax;

   const int numPatches = numberOfWeightPatches();
   for (int i = 0; i < numPatches; i++) {
      int xScale = post->clayer->xScale - pre->clayer->xScale;
      int yScale = post->clayer->xScale - pre->clayer->yScale;
      gaborWeights(wPatches[i], xScale, yScale, aspect, sigma, r2Max, lambda, strength);
   }

   return 0;
}

int GaborConn::gaborWeights(PVPatch * wp, int xScale, int yScale,
                            float aspect, float sigma, float r2Max, float lambda, float strength)
{
   PVParams * params = parent->parameters();

   float rotate = 1.0;
   float invert = 0.0;
   if (params->present(name, "rotate")) rotate = params->value(name, "rotate");
   if (params->present(name, "invert")) invert = params->value(name, "invert");

   pvdata_t * w = wp->data;

   const float phi = 0.0;  // phase

   const int nx = (int) wp->nx;
   const int ny = (int) wp->ny;
   const int nf = (int) wp->nf;

   const int sx = (int) wp->sx;  assert(sx == nf);
   const int sy = (int) wp->sy;  assert(sy == nf*nx);
   const int sf = (int) wp->sf;  assert(sf == 1);

   const float dx = powf(2, xScale);
   const float dy = powf(2, yScale);

   // pre-synaptic neuron is at the center of the patch (0,0)
   // (x0,y0) is at upper left corner of patch (i=0,j=0)
   const float x0 = -(nx/2.0 - 0.5) * dx;
   const float y0 = +(ny/2.0 - 0.5) * dy;

   const float dth = PI/nf;
   const float th0 = rotate*dth/2.0;

   for (int f = 0; f < nf; f++) {
      float th = th0 + f * dth;
      for (int j = 0; j < ny; j++) {
         float yp = y0 - j * dy;    // pixel coordinate
         for (int i = 0; i < nx; i++) {
            float xp  = x0 + i*dx;  // pixel coordinate

            // rotate the reference frame by th ((x,y) is center of patch (0,0))
            float u1 = + (0.0 - xp) * cos(th) + (0.0 - yp) * sin(th);
            float u2 = - (0.0 - xp) * sin(th) + (0.0 - yp) * cos(th);

            float factor = cos(2.0*PI*u2/lambda + phi);
            if (fabs(u2/lambda) > 3.0/4.0) factor = 0.0;  // phase < 3*PI/2 (no second positive band)
            float d2 = u1 * u1 + (aspect*u2 * aspect*u2);
            float wt = factor * expf(-d2 / (2.0*sigma*sigma));

#ifdef DEBUG_OUTPUT
            if (j == 0) printf("x=%f fac=%f w=%f\n", xp, factor, wt);
#endif
            if (xp*xp + yp*yp > r2Max) {
               w[i*sx + j*sy + f*sf] = 0.0;
            }
            else {
               if (invert) wt *= -1.0;
               if (wt < 0.0) wt = 0.0;       // clip negative values
               w[i*sx + j*sy + f*sf] = wt;
            }
         }
      }
   }

   // normalize
   for (int f = 0; f < nf; f++) {
      float sum = 0;
      for (int i = 0; i < nx*ny; i++) {
         if (w[f + i*nf] > 0.0) sum += w[f + i*nf];
      }

      if (sum == 0.0) continue;  // all weights == zero is ok

      float factor = strength/sum;
      for (int i = 0; i < nx*ny; i++) w[f + i*nf] *= factor;
   }

   return 0;
}

} // Namespace PV
<|endoftext|>


<commit_before>#include <time.h>
#include <stdlib.h>

#include "game_modes.hpp"

GameModes::GameModes(GameDesk *desk_point, IoBase *io_base_point) {
    desk_ = desk_point;
    iobase_ = io_base_point;
}

void GameModes::start(int argc, char *argv[]) {
    if (argc == 1) {
        help();
    }
    else if (*++argv[1] == 'w') {
        gameForWin();
    }
    else if (*argv[1] == 's') {
        gameForScore();
    }
    else if (*argv[1] == 't') {
        gameWithTime();
    }
    else {
        help();
    }
}

void GameModes::gameForWin() {
    int desk_size;
    desk_size = iobase_->getDeskSize();
    int win_number;
    win_number = iobase_->getWinNumber();
    setDesk(desk_size);
    iobase_->output();
    while (!checkFail() && !checkWin(win_number)) {
        play();
    }
    iobase_->finish(checkFail(), score());
}

void GameModes::gameForScore() {
    int desk_size;
    desk_size = iobase_->getDeskSize();
    setDesk(desk_size);
    iobase_->output();
    while (!checkFail()) {
        play();
    }
    iobase_->finish(checkFail(), score());
}

void GameModes::gameWithTime() {
    int desk_size;
    desk_size = iobase_->getDeskSize();
    int time_number;
    time_number = iobase_->getTimeNumber();
    setDesk(desk_size);
    int t1 = time(NULL);
    int t2 = 0;
    iobase_->output();
    while (!checkFail() && ((t2 - t1) < time_number * 60)) {
        play();
    }
    iobase_->finish(checkFail(), score());
}

void GameModes::help() {
    iobase_->sentHelpMessage();
}

void GameModes::setDesk(int desk_size) {
    int i, x;
    Point point;
    desk_->resize(desk_size);
    for (i = 0; i < desk_size; i++) {
        for (x = 0; x < desk_size; x++) {
            point.col = i;
            point.row = x;
            if (rand() <= (RAND_MAX / 2)) {
                desk_->setDeskNumber(point, 1);
            }
            else {
                desk_->setDeskNumber(point, 2);
            }
        }
    }
}

void GameModes::play() {
    Points points;
    Checker checker;
    points = iobase_->getIndex();
    if (checker.checkStep(*desk_, points)) {
        replace(points);
        iobase_->output();
    }
    else {
        iobase_->indexError();
    }
}

void GameModes::replace(Points& points) {
    int n1 = desk_->getDeskNumber(points.p1);
    int n2 = desk_->getDeskNumber(points.p2);
    desk_->setDeskNumber(points.p2, n2 * 2);
    while (points.p1.col < (desk_->getRowNumber() - 1)) {
        Points points_local;
        points_local = points;
        points_local.p1.col += 1;
        desk_->setDeskNumber(points.p1, desk_->getDeskNumber(points_local.p1));
        points.p1.col = points_local.p1.col;
    }
    if (rand() <= (RAND_MAX / 2)) {
        desk_->setDeskNumber(points.p1, 2);
    }
    else {
        desk_->setDeskNumber(points.p1, 1);
    }
}

long long int GameModes::score() {
    Point point;
    long long int all_score = 0;
    long long int row_score = 0;
    int i, x;
    for (i = 0; i < desk_->getRowNumber(); i++) {
        for (x = 0; x < desk_->getRowNumber(); x++) {
            point.col = i;
            point.row = x;
            row_score += desk_->getDeskNumber(point);
        }
        all_score += row_score;
        row_score = 0;
    }
    return all_score;
}

bool GameModes::checkWin(int for_win) {
    if (for_win <= score()) {
        return true;
    }
    return false;
}

bool GameModes::checkFail() {
    Points points;
    Checker checker;
    int i, x, z, t;
    for (i = 0; i < desk_->getRowNumber(); i++) {
        points.p1.col = i;
        for (x = 0; x < desk_->getRowNumber(); x++) {
            points.p1.row = x;
            for (z = 0; z < desk_->getRowNumber(); z++) {
                points.p2.col = z;
                for (t = 0; t < desk_->getRowNumber(); t++) {
                    points.p2.row = t;
                    if (checker.checkStep(*desk_, points)) {
                        return false;
                    }
                }
            }
        }
    }
    return true;
}
<commit_msg>correct method gameWithTime of GameModes<commit_after>#include <time.h>
#include <stdlib.h>

#include "game_modes.hpp"

GameModes::GameModes(GameDesk *desk_point, IoBase *io_base_point) {
    desk_ = desk_point;
    iobase_ = io_base_point;
}

void GameModes::start(int argc, char *argv[]) {
    if (argc == 1) {
        help();
    }
    else if (*++argv[1] == 'w') {
        gameForWin();
    }
    else if (*argv[1] == 's') {
        gameForScore();
    }
    else if (*argv[1] == 't') {
        gameWithTime();
    }
    else {
        help();
    }
}

void GameModes::gameForWin() {
    int desk_size;
    desk_size = iobase_->getDeskSize();
    int win_number;
    win_number = iobase_->getWinNumber();
    setDesk(desk_size);
    iobase_->output();
    while (!checkFail() && !checkWin(win_number)) {
        play();
    }
    iobase_->finish(checkFail(), score());
}

void GameModes::gameForScore() {
    int desk_size;
    desk_size = iobase_->getDeskSize();
    setDesk(desk_size);
    iobase_->output();
    while (!checkFail()) {
        play();
    }
    iobase_->finish(checkFail(), score());
}

void GameModes::gameWithTime() {
    int desk_size;
    desk_size = iobase_->getDeskSize();
    int time_number;
    time_number = iobase_->getTimeNumber();
    setDesk(desk_size);
    int t1 = time(NULL);
    int t2 = 0;
    iobase_->output();
    while (!checkFail() && ((t2 - t1) < time_number * 60)) {
        play();
        t2 = time(NULL);
    }
    iobase_->finish(checkFail(), score());
}

void GameModes::help() {
    iobase_->sentHelpMessage();
}

void GameModes::setDesk(int desk_size) {
    int i, x;
    Point point;
    desk_->resize(desk_size);
    for (i = 0; i < desk_size; i++) {
        for (x = 0; x < desk_size; x++) {
            point.col = i;
            point.row = x;
            if (rand() <= (RAND_MAX / 2)) {
                desk_->setDeskNumber(point, 1);
            }
            else {
                desk_->setDeskNumber(point, 2);
            }
        }
    }
}

void GameModes::play() {
    Points points;
    Checker checker;
    points = iobase_->getIndex();
    if (checker.checkStep(*desk_, points)) {
        replace(points);
        iobase_->output();
    }
    else {
        iobase_->indexError();
    }
}

void GameModes::replace(Points& points) {
    int n1 = desk_->getDeskNumber(points.p1);
    int n2 = desk_->getDeskNumber(points.p2);
    desk_->setDeskNumber(points.p2, n2 * 2);
    while (points.p1.col < (desk_->getRowNumber() - 1)) {
        Points points_local;
        points_local = points;
        points_local.p1.col += 1;
        desk_->setDeskNumber(points.p1, desk_->getDeskNumber(points_local.p1));
        points.p1.col = points_local.p1.col;
    }
    if (rand() <= (RAND_MAX / 2)) {
        desk_->setDeskNumber(points.p1, 2);
    }
    else {
        desk_->setDeskNumber(points.p1, 1);
    }
}

long long int GameModes::score() {
    Point point;
    long long int all_score = 0;
    long long int row_score = 0;
    int i, x;
    for (i = 0; i < desk_->getRowNumber(); i++) {
        for (x = 0; x < desk_->getRowNumber(); x++) {
            point.col = i;
            point.row = x;
            row_score += desk_->getDeskNumber(point);
        }
        all_score += row_score;
        row_score = 0;
    }
    return all_score;
}

bool GameModes::checkWin(int for_win) {
    if (for_win <= score()) {
        return true;
    }
    return false;
}

bool GameModes::checkFail() {
    Points points;
    Checker checker;
    int i, x, z, t;
    for (i = 0; i < desk_->getRowNumber(); i++) {
        points.p1.col = i;
        for (x = 0; x < desk_->getRowNumber(); x++) {
            points.p1.row = x;
            for (z = 0; z < desk_->getRowNumber(); z++) {
                points.p2.col = z;
                for (t = 0; t < desk_->getRowNumber(); t++) {
                    points.p2.row = t;
                    if (checker.checkStep(*desk_, points)) {
                        return false;
                    }
                }
            }
        }
    }
    return true;
}
<|endoftext|>


<commit_before>#include <algorithm>

#include <boost/filesystem.hpp>

#include <QMessageBox>
#include <QFileDialog>

#include "fish_annotator/db_uploader/database_info.h"
#include "fish_annotator/db_uploader/mainwindow.h"
#include "ui_mainwindow.h"

namespace fish_annotator { namespace db_uploader {

namespace fs = boost::filesystem;

namespace { //anonymous

static const std::vector<std::string> kDirExtensions = {
  ".jpg", ".png", ".bmp", ".tif", ".jpeg",
  ".JPG", ".PNG", ".BMP", ".TIF", ".JPEG"};

} // anonymous namespace

MainWindow::MainWindow(QWidget *parent)
  : ui_(new Ui::MainWindow)
  , input_db_(new QSqlDatabase())
  , output_db_(new QSqlDatabase()) {
  ui_->setupUi(this);
  setWindowTitle("Database Uploader");
#ifdef _WIN32
  setWindowIcon(QIcon(":/icons/cvision/cvision_no_text.ico"));
#endif
  fs::path current_path(QDir::currentPath().toStdString());
  fs::path default_input = current_path / fs::path("default.input_database");
  fs::path default_output = current_path / fs::path("default.output_database");
  if(fs::exists(default_input)) {
    DatabaseInfo input;
    deserialize(input, default_input.string());
    ui_->inputServer->setText(input.getServer().c_str());
    ui_->inputDatabase->setText(input.getDatabase().c_str());
    ui_->inputUsername->setText(input.getUsername().c_str());
  }
  if(fs::exists(default_output)) {
    DatabaseInfo output;
    deserialize(output, default_output.string());
    ui_->outputServer->setText(output.getServer().c_str());
    ui_->outputDatabase->setText(output.getDatabase().c_str());
    ui_->outputUsername->setText(output.getUsername().c_str());
  }
}

void MainWindow::on_connectInputDb_clicked() {
  ui_->inputDbStatus->setText("Attempting to connect...");
  ui_->inputDbStatus->repaint();
  *input_db_ = QSqlDatabase::addDatabase("QODBC3", "input");
  if(input_db_->isDriverAvailable("QODBC") == false) {
    QMessageBox err;
    err.critical(0, "Error", "ODBC driver is not available!");
  }
  input_db_->setDatabaseName(
      "DRIVER={SQL Server};SERVER={" + ui_->inputServer->text() +
      "};DATABASE=" + ui_->inputDatabase->text() +
      ";Trusted_Connection=no;user_id=" + ui_->inputUsername->text() +
      ";password=" + ui_->inputPassword->text() + ";WSID=.");
  if(input_db_->isValid() == false) {
    ui_->inputDbStatus->setText("Not connected");
    QMessageBox err;
    err.critical(0, "Error", "Not a valid database!");
  }
  if(input_db_->open() == false) {
    ui_->inputDbStatus->setText("Not connected");
    QMessageBox err;
    err.critical(0, "Error", input_db_->lastError().text());
  }
  else {
    ui_->inputDbStatus->setText("Connected");
  }
  if(output_db_->isOpen() == true && input_db_->isOpen() == true) {
    ui_->upload->setEnabled(true);
  }
}

void MainWindow::on_connectOutputDb_clicked() {
  ui_->outputDbStatus->setText("Attempting to connect...");
  ui_->outputDbStatus->repaint();
  *output_db_ = QSqlDatabase::addDatabase("QODBC3", "output");
  if(output_db_->isDriverAvailable("QODBC") == false) {
    QMessageBox err;
    err.critical(0, "Error", "ODBC driver is not available!");
  }
  output_db_->setDatabaseName(
      "DRIVER={SQL Server};SERVER={" + ui_->outputServer->text() +
      "};DATABASE=" + ui_->outputDatabase->text() +
      ";Trusted_Connection=no;user_id=" + ui_->outputUsername->text() +
      ";password=" + ui_->outputPassword->text() + ";WSID=.");
  if(output_db_->isValid() == false) {
    ui_->outputDbStatus->setText("Not connected");
    QMessageBox err;
    err.critical(0, "Error", "Not a valid database!");
  }
  if(output_db_->open() == false) {
    ui_->outputDbStatus->setText("Not connected");
    QMessageBox err;
    err.critical(0, "Error", output_db_->lastError().text());
  }
  else {
    ui_->outputDbStatus->setText("Connected");
  }
  if(output_db_->isOpen() == true && input_db_->isOpen() == true) {
    ui_->upload->setEnabled(true);
  }
}

void MainWindow::on_browseImageDir_clicked() {
  ui_->imageDirectory->setText(QFileDialog::getExistingDirectory(
    this, "Select annotated image directory"));
}

void MainWindow::on_cancel_clicked() {
  QApplication::quit();
}

void MainWindow::on_upload_clicked() {
}

#include "../../include/fish_annotator/db_uploader/moc_mainwindow.cpp"

}} // namespace fish_annotator::db_uploader

<commit_msg>Add preliminary upload implementation<commit_after>#include <algorithm>

#include <boost/filesystem.hpp>

#include <QMessageBox>
#include <QFileDialog>

#include "fish_annotator/db_uploader/database_info.h"
#include "fish_annotator/db_uploader/mainwindow.h"
#include "ui_mainwindow.h"

namespace fish_annotator { namespace db_uploader {

namespace fs = boost::filesystem;

namespace { //anonymous

static const std::vector<std::string> kDirExtensions = {
  ".jpg", ".png", ".bmp", ".tif", ".jpeg",
  ".JPG", ".PNG", ".BMP", ".TIF", ".JPEG"};

} // anonymous namespace

MainWindow::MainWindow(QWidget *parent)
  : ui_(new Ui::MainWindow)
  , input_db_(new QSqlDatabase())
  , output_db_(new QSqlDatabase()) {
  ui_->setupUi(this);
  setWindowTitle("Database Uploader");
#ifdef _WIN32
  setWindowIcon(QIcon(":/icons/cvision/cvision_no_text.ico"));
#endif
  fs::path current_path(QDir::currentPath().toStdString());
  fs::path default_input = current_path / fs::path("default.input_database");
  fs::path default_output = current_path / fs::path("default.output_database");
  if(fs::exists(default_input)) {
    DatabaseInfo input;
    deserialize(input, default_input.string());
    ui_->inputServer->setText(input.getServer().c_str());
    ui_->inputDatabase->setText(input.getDatabase().c_str());
    ui_->inputUsername->setText(input.getUsername().c_str());
  }
  if(fs::exists(default_output)) {
    DatabaseInfo output;
    deserialize(output, default_output.string());
    ui_->outputServer->setText(output.getServer().c_str());
    ui_->outputDatabase->setText(output.getDatabase().c_str());
    ui_->outputUsername->setText(output.getUsername().c_str());
  }
}

void MainWindow::on_connectInputDb_clicked() {
  ui_->inputDbStatus->setText("Attempting to connect...");
  ui_->inputDbStatus->repaint();
  *input_db_ = QSqlDatabase::addDatabase("QODBC3", "input");
  if(input_db_->isDriverAvailable("QODBC") == false) {
    QMessageBox err;
    err.critical(0, "Error", "ODBC driver is not available!");
  }
  input_db_->setDatabaseName(
      "DRIVER={SQL Server};SERVER={" + ui_->inputServer->text() +
      "};DATABASE=" + ui_->inputDatabase->text() +
      ";Trusted_Connection=no;user_id=" + ui_->inputUsername->text() +
      ";password=" + ui_->inputPassword->text() + ";WSID=.");
  if(input_db_->isValid() == false) {
    ui_->inputDbStatus->setText("Not connected");
    QMessageBox err;
    err.critical(0, "Error", "Not a valid database!");
  }
  if(input_db_->open() == false) {
    ui_->inputDbStatus->setText("Not connected");
    QMessageBox err;
    err.critical(0, "Error", input_db_->lastError().text());
  }
  else {
    ui_->inputDbStatus->setText("Connected");
  }
  if(output_db_->isOpen() == true && input_db_->isOpen() == true) {
    ui_->upload->setEnabled(true);
  }
}

void MainWindow::on_connectOutputDb_clicked() {
  ui_->outputDbStatus->setText("Attempting to connect...");
  ui_->outputDbStatus->repaint();
  *output_db_ = QSqlDatabase::addDatabase("QODBC3", "output");
  if(output_db_->isDriverAvailable("QODBC") == false) {
    QMessageBox err;
    err.critical(0, "Error", "ODBC driver is not available!");
  }
  output_db_->setDatabaseName(
      "DRIVER={SQL Server};SERVER={" + ui_->outputServer->text() +
      "};DATABASE=" + ui_->outputDatabase->text() +
      ";Trusted_Connection=no;user_id=" + ui_->outputUsername->text() +
      ";password=" + ui_->outputPassword->text() + ";WSID=.");
  if(output_db_->isValid() == false) {
    ui_->outputDbStatus->setText("Not connected");
    QMessageBox err;
    err.critical(0, "Error", "Not a valid database!");
  }
  if(output_db_->open() == false) {
    ui_->outputDbStatus->setText("Not connected");
    QMessageBox err;
    err.critical(0, "Error", output_db_->lastError().text());
  }
  else {
    ui_->outputDbStatus->setText("Connected");
  }
  if(output_db_->isOpen() == true && input_db_->isOpen() == true) {
    ui_->upload->setEnabled(true);
  }
}

void MainWindow::on_browseImageDir_clicked() {
  ui_->imageDirectory->setText(QFileDialog::getExistingDirectory(
    this, "Select annotated image directory"));
}

void MainWindow::on_cancel_clicked() {
  QApplication::quit();
}

void MainWindow::on_upload_clicked() {
  QString image_dir = ui_->imageDirectory->text();
  std::vector<boost::filesystem::path> image_files;
  fs::directory_iterator dir_it(image_dir.toStdString());
  fs::directory_iterator dir_end;
  for(; dir_it != dir_end; ++dir_it) {
    fs::path ext(dir_it->path().extension());
    for(auto &ok_ext : kDirExtensions) {
      if(ext == ok_ext) {
        image_files.push_back(dir_it->path());
      }
    }
  }
  std::sort(image_files.begin(), image_files.end());
}

#include "../../include/fish_annotator/db_uploader/moc_mainwindow.cpp"

}} // namespace fish_annotator::db_uploader

<|endoftext|>