<commit_before>/* http_bidder_interface.cc
   Eric Robert, 2 April 2014
   Copyright (c) 2011 Datacratic.  All rights reserved.
*/

#include "http_bidder_interface.h"
#include "jml/db/persistent.h"
#include "soa/service/http_client.h"
#include "soa/utils/generic_utils.h"
#include "rtbkit/common/messages.h"
#include "rtbkit/plugins/bid_request/openrtb_bid_request.h"
#include "rtbkit/openrtb/openrtb_parsing.h"
#include "rtbkit/core/router/router.h"

using namespace Datacratic;
using namespace RTBKIT;

namespace {
    DefaultDescription<OpenRTB::BidRequest> desc;

    std::string httpErrorString(HttpClientError code)  {
        switch (code) {
            #define CASE(code) \
                case code: \
                    return #code;
            CASE(HttpClientError::NONE)
            CASE(HttpClientError::UNKNOWN)
            CASE(HttpClientError::TIMEOUT)
            CASE(HttpClientError::HOST_NOT_FOUND)
            CASE(HttpClientError::COULD_NOT_CONNECT)
            #undef CASE
        }
        ExcCheck(false, "Invalid code path");
        return "";
    }
}

namespace RTBKIT {

Logging::Category HttpBidderInterface::print("HttpBidderInterface");
Logging::Category HttpBidderInterface::error("HttpBidderInterface Error", HttpBidderInterface::print);
Logging::Category HttpBidderInterface::trace("HttpBidderInterface Trace", HttpBidderInterface::print);

}

HttpBidderInterface::HttpBidderInterface(std::string name,
                                         std::shared_ptr<ServiceProxies> proxies,
                                         Json::Value const & json)
        : BidderInterface(proxies, name) {

    try {
        routerHost = json["router"]["host"].asString();
        routerPath = json["router"]["path"].asString();
        adserverHost = json["adserver"]["host"].asString();
        adserverWinPort = json["adserver"]["winPort"].asInt();
        adserverEventPort = json["adserver"]["eventPort"].asInt();
    } catch (const std::exception & e) {
        THROW(error) << "configuration file is invalid" << std::endl
                   << "usage : " << std::endl
                   << "{" << std::endl << "\t\"router\" : {" << std::endl
                   << "\t\t\"host\" : <string : hostname with port>" << std::endl
                   << "\t\t\"path\" : <string : resource name>" << std::endl
                   << "\t}" << std::endl << "\t{" << std::endl
                   << "\t{" << std::endl << "\t\"adserver\" : {" << std::endl
                   << "\t\t\"host\" : <string : hostname>" << std::endl
                   << "\t\t\"winPort\" : <int : winPort>" << std::endl
                   << "\t\t\"eventPort\" : <int eventPort>" << std::endl
                   << "\t}" << std::endl << "}";
    }

    httpClientRouter.reset(new HttpClient(routerHost));
    loop.addSource("HttpBidderInterface::httpClientRouter", httpClientRouter);

    std::string winHost = adserverHost + ':' + std::to_string(adserverWinPort);
    httpClientAdserverWins.reset(new HttpClient(winHost));
    loop.addSource("HttpBidderInterface::httpClientAdserverWins", httpClientAdserverWins);

    std::string eventHost = adserverHost + ':' + std::to_string(adserverEventPort);
    httpClientAdserverEvents.reset(new HttpClient(eventHost));
    loop.addSource("HttpBidderInterface::httpClientAdserverEvents", httpClientAdserverEvents);

}

HttpBidderInterface::~HttpBidderInterface()
{
    shutdown();
}

void HttpBidderInterface::start() {
    loop.start();
}

void HttpBidderInterface::shutdown() {
    loop.shutdown();
}

void HttpBidderInterface::sendAuctionMessage(std::shared_ptr<Auction> const & auction,
                                             double timeLeftMs,
                                             std::map<std::string, BidInfo> const & bidders) {
    using namespace std;
    for(auto & item : bidders) {
        auto & agent = item.first;
        auto & info = router->agents[agent];
        const auto &config = info.config;
        BidRequest originalRequest = *auction->request;
        WinCostModel wcm = auction->exchangeConnector->getWinCostModel(*auction, *info.config);

        OpenRTB::BidRequest openRtbRequest = toOpenRtb(originalRequest);
        bool ok = prepareRequest(openRtbRequest, originalRequest, bidders);
        /* If we took too much time processing the request, then we don't send it.  */
        if (!ok) {
            return;
        }
        StructuredJsonPrintingContext context;
        desc.printJson(&openRtbRequest, context);
        auto requestStr = context.output.toString();

        /* We need to capture by copy inside the lambda otherwise we might get
           a dangling reference if we go out of scope before receiving the http response
        */
        auto callbacks = std::make_shared<HttpClientSimpleCallbacks>(
                [=](const HttpRequest &, HttpClientError errorCode,
                    int statusCode, const std::string &, std::string &&body)
                {
                    if (errorCode != HttpClientError::NONE) {
                        router->throwException("http", "Error requesting %s: %s",
                                               routerHost.c_str(),
                                               httpErrorString(errorCode).c_str());
                      }
                      else if (statusCode == 200) {
                        // cerr << "Response: " << body << std::endl;
                         OpenRTB::BidResponse response;
                         ML::Parse_Context context("payload",
                               body.c_str(), body.size());
                         StreamingJsonParsingContext jsonContext(context);
                         static DefaultDescription<OpenRTB::BidResponse> respDesc;
                         respDesc.parseJson(&response, jsonContext);

                         for (const auto &seatbid: response.seatbid) {
                             Bids bids;

                             for (const auto &bid: seatbid.bid) {
                                 Bid theBid;

                                 int crid = bid.crid.toInt();
                                 int creativeIndex = indexOf(config->creatives,
                                     &Creative::id, crid);

                                 if (creativeIndex == -1) {
                                     router->throwException("http.response",
                                        "Unknown creative id: %d", crid);
                                 }

                                 theBid.creativeIndex = creativeIndex;
                                 theBid.price = USD_CPM(bid.price.val);
                                 theBid.priority = 0.0;

                                 int spotIndex = indexOf(openRtbRequest.imp,
                                                        &OpenRTB::Impression::id, bid.impid);
                                 if (spotIndex == -1) {
                                      router->throwException("http.response",
                                         "Unknown impression id: %s",
                                         bid.impid.toString().c_str());
                                 }

                                 theBid.spotIndex = spotIndex;

                                 bids.push_back(std::move(theBid));
                             }
                             submitBids(agent, auction->id, bids, wcm);
                         }
                     }
                }
        );

        HttpRequest::Content reqContent { requestStr, "application/json" };
        RestParams headers { { "x-openrtb-version", "2.1" } };
       // std::cerr << "Sending HTTP POST to: " << routerHost << " " << routerPath << std::endl;
       // std::cerr << "Content " << reqContent.str << std::endl;

        httpClientRouter->post(routerPath, callbacks, reqContent,
                         { } /* queryParams */, headers);
    }
}

void HttpBidderInterface::sendLossMessage(std::string const & agent,
                                          std::string const & id) {

}

void HttpBidderInterface::sendWinLossMessage(MatchedWinLoss const & event) {
    if (event.type == MatchedWinLoss::Loss) return;

    auto callbacks = std::make_shared<HttpClientSimpleCallbacks>(
        [=](const HttpRequest &, HttpClientError errorCode,
            int statusCode, const std::string &, std::string &&body)
        {
            if (errorCode != HttpClientError::NONE) {
                throw ML::Exception("Error requesting %s:%d '%s'",
                                    adserverHost.c_str(),
                                    adserverWinPort,
                                    httpErrorString(errorCode).c_str());
              }
        });

    Json::Value content;

    content["timestamp"] = event.timestamp.secondsSinceEpoch();
    content["bidRequestId"] = event.auctionId.toString();
    content["impid"] = event.impId.toString();
    content["userIds"] = event.uids.toJson();
    // ratio cannot be casted to json::value ...
    content["price"] = (double) getAmountIn<CPM>(event.winPrice);

    //requestStr["passback"];

    HttpRequest::Content reqContent { content, "application/json" };
    httpClientAdserverWins->post("/", callbacks, reqContent,
                         { } /* queryParams */);

}

void HttpBidderInterface::sendBidLostMessage(std::string const & agent,
                                             std::shared_ptr<Auction> const & auction) {
}

void HttpBidderInterface::sendCampaignEventMessage(std::string const & agent,
                                                   MatchedCampaignEvent const & event) {
    auto callbacks = std::make_shared<HttpClientSimpleCallbacks>(
        [=](const HttpRequest &, HttpClientError errorCode,
            int statusCode, const std::string &, std::string &&body)
        {
            if (errorCode != HttpClientError::NONE) {
                throw ML::Exception("Error requesting %s:%d '%s'",
                                    adserverHost.c_str(),
                                    adserverEventPort,
                                    httpErrorString(errorCode).c_str());
              }
        });

    Json::Value content;

    content["timestamp"] = event.timestamp.secondsSinceEpoch();
    content["bidRequestId"] = event.auctionId.toString();
    content["impid"] = event.impId.toString();
    content["type"] = event.label;

    HttpRequest::Content reqContent { content, "application/json" };
    httpClientAdserverEvents->post("/", callbacks, reqContent,
                         { } /* queryParams */);

}

void HttpBidderInterface::sendBidDroppedMessage(std::string const & agent,
                                                std::shared_ptr<Auction> const & auction) {
}

void HttpBidderInterface::sendBidInvalidMessage(std::string const & agent,
                                                std::string const & reason,
                                                std::shared_ptr<Auction> const & auction) {
}

void HttpBidderInterface::sendNoBudgetMessage(std::string const & agent,
                                              std::shared_ptr<Auction> const & auction) {
}

void HttpBidderInterface::sendTooLateMessage(std::string const & agent,
                                             std::shared_ptr<Auction> const & auction) {
}

void HttpBidderInterface::sendMessage(std::string const & agent,
                                      std::string const & message) {
}

void HttpBidderInterface::sendErrorMessage(std::string const & agent,
                                           std::string const & error,
                                           std::vector<std::string> const & payload) {
}

void HttpBidderInterface::sendPingMessage(std::string const & agent,
                                          int ping) {
    ExcCheck(ping == 0 || ping == 1, "Bad PING level, must be either 0 or 1");

    auto encodeDate = [](Date date) {
        return ML::format("%.5f", date.secondsSinceEpoch());
    };

    const std::string sentTime = encodeDate(Date::now());
    const std::string receivedTime = sentTime;
    const std::string pong = (ping == 0 ? "PONG0" : "PONG1");
    std::vector<std::string> message { agent, pong, sentTime, receivedTime };
    router->handleAgentMessage(message);
}

void HttpBidderInterface::tagRequest(OpenRTB::BidRequest &request,
                                     const std::map<std::string, BidInfo> &bidders) const
{

    for (const auto &bidder: bidders) {
        const auto &agentConfig = bidder.second.agentConfig;
        const auto &spots = bidder.second.imp;

        for (const auto &spot: spots) {
            const int adSpotIndex = spot.first;
            ExcCheck(adSpotIndex >= 0 && adSpotIndex < request.imp.size(),
                     "adSpotIndex out of range");
            auto &imp = request.imp[adSpotIndex];
            auto &ext = imp.ext;

            ext["external-ids"].append(agentConfig->externalId);
        }

    }

}

bool HttpBidderInterface::prepareRequest(OpenRTB::BidRequest &request,
                                         const RTBKIT::BidRequest &originalRequest,
                                         const std::map<std::string, BidInfo> &bidders) const {
    tagRequest(request, bidders);

    // We update the tmax value before sending the BidRequest to substract our processing time
    double processingTimeMs = originalRequest.timestamp.secondsUntil(Date::now()) * 1000;
    int oldTmax = request.tmax.value();
    int newTmax = oldTmax - static_cast<int>(std::round(processingTimeMs));
    if (newTmax <= 0) {
        return false;
    }
#if 0
        std::cerr << "old tmax = " << oldTmax << std::std::endl
                  << "new tmax = " << newTmax << std::std::endl;
#endif
    ExcCheck(newTmax <= oldTmax, "Wrong tmax calculation");
    request.tmax.val = newTmax;
    return true;
}

void HttpBidderInterface::submitBids(const std::string &agent, Id auctionId,
                                     const Bids &bids, WinCostModel wcm)
{
     Json::FastWriter writer;
     std::vector<std::string> message { agent, "BID" };
     message.push_back(auctionId.toString());
     std::string bidsStr = writer.write(bids.toJson());
     std::string wcmStr = writer.write(wcm.toJson());
     message.push_back(std::move(bidsStr));
     message.push_back(std::move(wcmStr));

     router->doBid(message);
}

//
// factory
//

namespace {

struct AtInit {
    AtInit()
    {
        BidderInterface::registerFactory("http", [](std::string const & name , std::shared_ptr<ServiceProxies> const & proxies, Json::Value const & json) {
            return new HttpBidderInterface(name, proxies, json);
        });
    }
} atInit;

}

<commit_msg>HttpBidderInterface now sends only one HTTP request and uses the Bid extension field to lookup the correct agent and AgentConfig<commit_after>/* http_bidder_interface.cc
   Eric Robert, 2 April 2014
   Copyright (c) 2011 Datacratic.  All rights reserved.
*/

#include "http_bidder_interface.h"
#include "jml/db/persistent.h"
#include "soa/service/http_client.h"
#include "soa/utils/generic_utils.h"
#include "rtbkit/common/messages.h"
#include "rtbkit/plugins/bid_request/openrtb_bid_request.h"
#include "rtbkit/openrtb/openrtb_parsing.h"
#include "rtbkit/core/router/router.h"

using namespace Datacratic;
using namespace RTBKIT;

namespace {
    DefaultDescription<OpenRTB::BidRequest> desc;

    std::string httpErrorString(HttpClientError code)  {
        switch (code) {
            #define CASE(code) \
                case code: \
                    return #code;
            CASE(HttpClientError::NONE)
            CASE(HttpClientError::UNKNOWN)
            CASE(HttpClientError::TIMEOUT)
            CASE(HttpClientError::HOST_NOT_FOUND)
            CASE(HttpClientError::COULD_NOT_CONNECT)
            #undef CASE
        }
        ExcCheck(false, "Invalid code path");
        return "";
    }
}

namespace RTBKIT {

Logging::Category HttpBidderInterface::print("HttpBidderInterface");
Logging::Category HttpBidderInterface::error("HttpBidderInterface Error", HttpBidderInterface::print);
Logging::Category HttpBidderInterface::trace("HttpBidderInterface Trace", HttpBidderInterface::print);

}

HttpBidderInterface::HttpBidderInterface(std::string name,
                                         std::shared_ptr<ServiceProxies> proxies,
                                         Json::Value const & json)
        : BidderInterface(proxies, name) {

    try {
        routerHost = json["router"]["host"].asString();
        routerPath = json["router"]["path"].asString();
        adserverHost = json["adserver"]["host"].asString();
        adserverWinPort = json["adserver"]["winPort"].asInt();
        adserverEventPort = json["adserver"]["eventPort"].asInt();
    } catch (const std::exception & e) {
        THROW(error) << "configuration file is invalid" << std::endl
                   << "usage : " << std::endl
                   << "{" << std::endl << "\t\"router\" : {" << std::endl
                   << "\t\t\"host\" : <string : hostname with port>" << std::endl
                   << "\t\t\"path\" : <string : resource name>" << std::endl
                   << "\t}" << std::endl << "\t{" << std::endl
                   << "\t{" << std::endl << "\t\"adserver\" : {" << std::endl
                   << "\t\t\"host\" : <string : hostname>" << std::endl
                   << "\t\t\"winPort\" : <int : winPort>" << std::endl
                   << "\t\t\"eventPort\" : <int eventPort>" << std::endl
                   << "\t}" << std::endl << "}";
    }

    httpClientRouter.reset(new HttpClient(routerHost));
    loop.addSource("HttpBidderInterface::httpClientRouter", httpClientRouter);

    std::string winHost = adserverHost + ':' + std::to_string(adserverWinPort);
    httpClientAdserverWins.reset(new HttpClient(winHost));
    loop.addSource("HttpBidderInterface::httpClientAdserverWins", httpClientAdserverWins);

    std::string eventHost = adserverHost + ':' + std::to_string(adserverEventPort);
    httpClientAdserverEvents.reset(new HttpClient(eventHost));
    loop.addSource("HttpBidderInterface::httpClientAdserverEvents", httpClientAdserverEvents);

}

HttpBidderInterface::~HttpBidderInterface()
{
    shutdown();
}

void HttpBidderInterface::start() {
    loop.start();
}

void HttpBidderInterface::shutdown() {
    loop.shutdown();
}

void HttpBidderInterface::sendAuctionMessage(std::shared_ptr<Auction> const & auction,
                                             double timeLeftMs,
                                             std::map<std::string, BidInfo> const & bidders) {
    using namespace std;

    auto findAgent = [&](uint64_t externalId)
        -> pair<string, shared_ptr<const AgentConfig>> {

        auto it =
        find_if(begin(bidders), end(bidders),
                [&](const pair<string, BidInfo> &bidder)
        {
            std::string agent = bidder.first;
            const auto &info = router->agents[agent];
            return info.config->externalId == externalId;
        });

        if (it == end(bidders)) {
            return make_pair("", nullptr);
        }

        return make_pair(it->first, it->second.agentConfig);

    };

    BidRequest originalRequest = *auction->request;
    OpenRTB::BidRequest openRtbRequest = toOpenRtb(originalRequest);
    bool ok = prepareRequest(openRtbRequest, originalRequest, bidders);
    /* If we took too much time processing the request, then we don't send it.  */
    if (!ok) {
        return;
    }
    StructuredJsonPrintingContext context;
    desc.printJson(&openRtbRequest, context);
    auto requestStr = context.output.toString();

    /* We need to capture by copy inside the lambda otherwise we might get
       a dangling reference if we go out of scope before receiving the http response
    */
    auto callbacks = std::make_shared<HttpClientSimpleCallbacks>(
            [=](const HttpRequest &, HttpClientError errorCode,
                int statusCode, const std::string &, std::string &&body)
            {
                if (errorCode != HttpClientError::NONE) {
                    router->throwException("http", "Error requesting %s: %s",
                                           routerHost.c_str(),
                                           httpErrorString(errorCode).c_str());
                  }
                  else if (statusCode == 200) {
                    // cerr << "Response: " << body << endl;
                     OpenRTB::BidResponse response;
                     ML::Parse_Context context("payload",
                           body.c_str(), body.size());
                     StreamingJsonParsingContext jsonContext(context);
                     static DefaultDescription<OpenRTB::BidResponse> respDesc;
                     respDesc.parseJson(&response, jsonContext);

                     for (const auto &seatbid: response.seatbid) {

                         for (const auto &bid: seatbid.bid) {
                             if (!bid.ext.isMember("external-id"))
                             {
                                 router->throwException("http.response",
                                    "Missing external-id ext field in BidResponse");
                             }

                             uint64_t externalId = bid.ext["external-id"].asUInt();

                             string agent;
                             shared_ptr<const AgentConfig> config;
                             tie(agent, config) = findAgent(externalId);
                             if (config == nullptr) {
                                 router->throwException("http.response",
                                    "Couldn't find config for externalId: %lu",
                                    externalId);
                             }

                             Bids bids;
                             Bid theBid;

                             int crid = bid.crid.toInt();
                             int creativeIndex = indexOf(config->creatives,
                                 &Creative::id, crid);

                             if (creativeIndex == -1) {
                                 router->throwException("http.response",
                                    "Unknown creative id: %d", crid);
                             }

                             theBid.creativeIndex = creativeIndex;
                             theBid.price = USD_CPM(bid.price.val);
                             theBid.priority = 0.0;

                             int spotIndex = indexOf(openRtbRequest.imp,
                                                    &OpenRTB::Impression::id, bid.impid);
                             if (spotIndex == -1) {
                                  router->throwException("http.response",
                                     "Unknown impression id: %s",
                                     bid.impid.toString().c_str());
                             }

                             theBid.spotIndex = spotIndex;

                             bids.push_back(std::move(theBid));

                             WinCostModel wcm =
                                 auction->exchangeConnector->getWinCostModel(*auction, *config);

                             submitBids(agent, auction->id, bids, wcm);
                         }
                     }
                 }
            }
    );

    HttpRequest::Content reqContent { requestStr, "application/json" };
    RestParams headers { { "x-openrtb-version", "2.1" } };
   // std::cerr << "Sending HTTP POST to: " << host << " " << path << std::endl;
   // std::cerr << "Content " << reqContent.str << std::endl;

    httpClientRouter->post(routerPath, callbacks, reqContent,
                     { } /* queryParams */, headers);
}

void HttpBidderInterface::sendLossMessage(std::string const & agent,
                                          std::string const & id) {

}

void HttpBidderInterface::sendWinLossMessage(MatchedWinLoss const & event) {
    if (event.type == MatchedWinLoss::Loss) return;

    auto callbacks = std::make_shared<HttpClientSimpleCallbacks>(
        [=](const HttpRequest &, HttpClientError errorCode,
            int statusCode, const std::string &, std::string &&body)
        {
            if (errorCode != HttpClientError::NONE) {
                throw ML::Exception("Error requesting %s:%d '%s'",
                                    adserverHost.c_str(),
                                    adserverWinPort,
                                    httpErrorString(errorCode).c_str());
              }
        });

    Json::Value content;

    content["timestamp"] = event.timestamp.secondsSinceEpoch();
    content["bidRequestId"] = event.auctionId.toString();
    content["impid"] = event.impId.toString();
    content["userIds"] = event.uids.toJson();
    // ratio cannot be casted to json::value ...
    content["price"] = (double) getAmountIn<CPM>(event.winPrice);

    //requestStr["passback"];

    HttpRequest::Content reqContent { content, "application/json" };
    httpClientAdserverWins->post("/", callbacks, reqContent,
                         { } /* queryParams */);

}

void HttpBidderInterface::sendBidLostMessage(std::string const & agent,
                                             std::shared_ptr<Auction> const & auction) {
}

void HttpBidderInterface::sendCampaignEventMessage(std::string const & agent,
                                                   MatchedCampaignEvent const & event) {
    auto callbacks = std::make_shared<HttpClientSimpleCallbacks>(
        [=](const HttpRequest &, HttpClientError errorCode,
            int statusCode, const std::string &, std::string &&body)
        {
            if (errorCode != HttpClientError::NONE) {
                throw ML::Exception("Error requesting %s:%d '%s'",
                                    adserverHost.c_str(),
                                    adserverEventPort,
                                    httpErrorString(errorCode).c_str());
              }
        });

    Json::Value content;

    content["timestamp"] = event.timestamp.secondsSinceEpoch();
    content["bidRequestId"] = event.auctionId.toString();
    content["impid"] = event.impId.toString();
    content["type"] = event.label;

    HttpRequest::Content reqContent { content, "application/json" };
    httpClientAdserverEvents->post("/", callbacks, reqContent,
                         { } /* queryParams */);

}

void HttpBidderInterface::sendBidDroppedMessage(std::string const & agent,
                                                std::shared_ptr<Auction> const & auction) {
}

void HttpBidderInterface::sendBidInvalidMessage(std::string const & agent,
                                                std::string const & reason,
                                                std::shared_ptr<Auction> const & auction) {
}

void HttpBidderInterface::sendNoBudgetMessage(std::string const & agent,
                                              std::shared_ptr<Auction> const & auction) {
}

void HttpBidderInterface::sendTooLateMessage(std::string const & agent,
                                             std::shared_ptr<Auction> const & auction) {
}

void HttpBidderInterface::sendMessage(std::string const & agent,
                                      std::string const & message) {
}

void HttpBidderInterface::sendErrorMessage(std::string const & agent,
                                           std::string const & error,
                                           std::vector<std::string> const & payload) {
}

void HttpBidderInterface::sendPingMessage(std::string const & agent,
                                          int ping) {
    ExcCheck(ping == 0 || ping == 1, "Bad PING level, must be either 0 or 1");

    auto encodeDate = [](Date date) {
        return ML::format("%.5f", date.secondsSinceEpoch());
    };

    const std::string sentTime = encodeDate(Date::now());
    const std::string receivedTime = sentTime;
    const std::string pong = (ping == 0 ? "PONG0" : "PONG1");
    std::vector<std::string> message { agent, pong, sentTime, receivedTime };
    router->handleAgentMessage(message);
}

void HttpBidderInterface::tagRequest(OpenRTB::BidRequest &request,
                                     const std::map<std::string, BidInfo> &bidders) const
{

    for (const auto &bidder: bidders) {
        const auto &agentConfig = bidder.second.agentConfig;
        const auto &spots = bidder.second.imp;

        for (const auto &spot: spots) {
            const int adSpotIndex = spot.first;
            ExcCheck(adSpotIndex >= 0 && adSpotIndex < request.imp.size(),
                     "adSpotIndex out of range");
            auto &imp = request.imp[adSpotIndex];
            auto &ext = imp.ext;

            ext["external-ids"].append(agentConfig->externalId);
        }

    }

}

bool HttpBidderInterface::prepareRequest(OpenRTB::BidRequest &request,
                                         const RTBKIT::BidRequest &originalRequest,
                                         const std::map<std::string, BidInfo> &bidders) const {
    tagRequest(request, bidders);

    // We update the tmax value before sending the BidRequest to substract our processing time
    double processingTimeMs = originalRequest.timestamp.secondsUntil(Date::now()) * 1000;
    int oldTmax = request.tmax.value();
    int newTmax = oldTmax - static_cast<int>(std::round(processingTimeMs));
    if (newTmax <= 0) {
        return false;
    }
#if 0
        std::cerr << "old tmax = " << oldTmax << std::std::endl
                  << "new tmax = " << newTmax << std::std::endl;
#endif
    ExcCheck(newTmax <= oldTmax, "Wrong tmax calculation");
    request.tmax.val = newTmax;
    return true;
}

void HttpBidderInterface::submitBids(const std::string &agent, Id auctionId,
                                     const Bids &bids, WinCostModel wcm)
{
     Json::FastWriter writer;
     std::vector<std::string> message { agent, "BID" };
     message.push_back(auctionId.toString());
     std::string bidsStr = writer.write(bids.toJson());
     std::string wcmStr = writer.write(wcm.toJson());
     message.push_back(std::move(bidsStr));
     message.push_back(std::move(wcmStr));

     router->doBid(message);
}

//
// factory
//

namespace {

struct AtInit {
    AtInit()
    {
        BidderInterface::registerFactory("http", [](std::string const & name , std::shared_ptr<ServiceProxies> const & proxies, Json::Value const & json) {
            return new HttpBidderInterface(name, proxies, json);
        });
    }
} atInit;

}

<|endoftext|>


<commit_before>#pragma once
#include "vector.hpp"
#include "angle.hpp"
#include "quaternion.hpp"

namespace frea {
	template <class T, bool A>
	struct ExpQuatT : Data<T,3,A>, op::Operator_Ne<ExpQuatT<T,A>> {
		using op_t = op::Operator_Ne<ExpQuatT<T,A>>;
		using base_t = Data<T,3,A>;
		using base_t::base_t;
		using rad_t = Radian<T>;
		using value_t = typename base_t::value_t;
		using vec_t = Vec_t<T,3,A>;
		using quat_t = QuatT<T,A>;

		ExpQuatT() = default;
		constexpr ExpQuatT(const quat_t& q) noexcept {
			constexpr auto Th = ThresholdF<value_t>(0.1);
			if(std::abs(q.w) >= 1.0-Th &&
				std::abs(q.x)+std::abs(q.y)+std::abs(q.z) <= Th)
			{
				// 無回転クォータニオンとみなす
				this->x = this->y = this->z = 0;
			} else {
				const value_t theta = std::acos(q.w);
				asVec3() = q.getAxis() * vec_t(theta);
			}
		}
		template <class T2, bool A2>
		constexpr ExpQuatT(const ExpQuatT<T2,A2>& q) noexcept:
			base_t(static_cast<const base_t&>(q))
		{}
		quat_t asQuat() const {
			const auto ret = getAngAxis();
			return quat_t::Rotation(ret.axis, ret.angle);
		}

		#define DEF_OP(op)	\
			ExpQuatT operator op (const ExpQuatT& e) const { \
				return asVec3() op e.asVec3(); \
			} \
			ExpQuatT operator op (const value_t& s) const { \
				return asVec3() op s; \
			} \
			using op_t::operator op;
		DEF_OP(+)
		DEF_OP(-)
		DEF_OP(*)
		DEF_OP(/)
		#undef DEF_OP

		bool operator == (const ExpQuatT& q) const {
			return asVec3() == q.asVec3();
		}
		value_t len_sq() const {
			return asVec3().len_sq();
		}
		value_t length() const {
			return asVec3().length();
		}
		vec_t& asVec3() noexcept {
			return reinterpret_cast<vec_t&>(*this);
		}
		const vec_t& asVec3() const noexcept {
			return reinterpret_cast<const vec_t&>(*this);
		}
		auto getAngAxis() const {
			struct {
				rad_t	angle;
				vec_t	axis;
			} ret;
			ret.axis = asVec3();
			const value_t theta = ret.axis.length();		// = (angle/2)
			if(theta < ThresholdF<value_t>(0.1)) {
				// 無回転クォータニオンとする
				ret.angle = rad_t(0);
				ret.axis = vec_t(1,0,0);
			} else {
				ret.axis /= theta;
				ret.angle = rad_t(theta*2);
			}
			return ret;
		}
	};

	using ExpQuat = ExpQuatT<float, false>;
	using AExpQuat = ExpQuatT<float, true>;
	using DExpQuat = ExpQuatT<double, false>;
	using ADExpQuat = ExpQuatT<double, true>;
}
<commit_msg>expquat: noexcept指定とコメント付加<commit_after>#pragma once
#include "vector.hpp"
#include "angle.hpp"
#include "quaternion.hpp"

namespace frea {
	template <class T, bool A>
	struct ExpQuatT : Data<T,3,A>, op::Operator_Ne<ExpQuatT<T,A>> {
		using op_t = op::Operator_Ne<ExpQuatT<T,A>>;
		using base_t = Data<T,3,A>;
		using base_t::base_t;
		using rad_t = Radian<T>;
		using value_t = typename base_t::value_t;
		using vec_t = Vec_t<T,3,A>;
		using quat_t = QuatT<T,A>;

		ExpQuatT() = default;
		constexpr ExpQuatT(const quat_t& q) {
			constexpr auto Th = ThresholdF<value_t>(0.1);
			if(std::abs(q.w) >= 1.0-Th &&
				std::abs(q.x)+std::abs(q.y)+std::abs(q.z) <= Th)
			{
				// 無回転クォータニオンとみなす
				this->x = this->y = this->z = 0;
			} else {
				const value_t theta = std::acos(q.w);
				asVec3() = q.getAxis() * vec_t(theta);
			}
		}
		//! 異なる内部形式、アラインメントからの変換
		template <class T2, bool A2>
		constexpr ExpQuatT(const ExpQuatT<T2,A2>& q) noexcept:
			base_t(static_cast<const base_t&>(q))
		{}
		quat_t asQuat() const noexcept {
			const auto ret = getAngAxis();
			return quat_t::Rotation(ret.axis, ret.angle);
		}

		#define DEF_OP(op)	\
			ExpQuatT operator op (const ExpQuatT& e) const noexcept { \
				return asVec3() op e.asVec3(); \
			} \
			ExpQuatT operator op (const value_t& s) const noexcept { \
				return asVec3() op s; \
			} \
			using op_t::operator op;
		DEF_OP(+)
		DEF_OP(-)
		DEF_OP(*)
		DEF_OP(/)
		#undef DEF_OP

		bool operator == (const ExpQuatT& q) const noexcept {
			return asVec3() == q.asVec3();
		}
		value_t len_sq() const noexcept {
			return asVec3().len_sq();
		}
		value_t length() const noexcept {
			return asVec3().length();
		}
		vec_t& asVec3() noexcept {
			return reinterpret_cast<vec_t&>(*this);
		}
		const vec_t& asVec3() const noexcept {
			return reinterpret_cast<const vec_t&>(*this);
		}
		auto getAngAxis() const noexcept {
			struct {
				rad_t	angle;
				vec_t	axis;
			} ret;
			ret.axis = asVec3();
			const value_t theta = ret.axis.length();		// = (angle/2)
			if(theta < ThresholdF<value_t>(0.1)) {
				// 無回転クォータニオンとする
				ret.angle = rad_t(0);
				ret.axis = vec_t(1,0,0);
			} else {
				ret.axis /= theta;
				ret.angle = rad_t(theta*2);
			}
			return ret;
		}
	};

	using ExpQuat = ExpQuatT<float, false>;
	using AExpQuat = ExpQuatT<float, true>;
	using DExpQuat = ExpQuatT<double, false>;
	using ADExpQuat = ExpQuatT<double, true>;
}
<|endoftext|>


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

#include "app/resource_bundle.h"

#include <atlbase.h>

#include "app/app_paths.h"
#include "app/gfx/font.h"
#include "app/l10n_util.h"
#include "base/file_util.h"
#include "base/logging.h"
#include "base/path_service.h"
#include "base/resource_util.h"
#include "base/string_piece.h"
#include "base/win_util.h"

namespace {

// Returns the flags that should be passed to LoadLibraryEx.
DWORD GetDataDllLoadFlags() {
  if (win_util::GetWinVersion() >= win_util::WINVERSION_VISTA)
    return LOAD_LIBRARY_AS_DATAFILE_EXCLUSIVE | LOAD_LIBRARY_AS_IMAGE_RESOURCE;

  return DONT_RESOLVE_DLL_REFERENCES;
}

}  // end anonymous namespace

ResourceBundle::~ResourceBundle() {
  FreeImages();

  if (locale_resources_data_) {
    BOOL rv = FreeLibrary(locale_resources_data_);
    DCHECK(rv);
  }
  if (theme_data_) {
    BOOL rv = FreeLibrary(theme_data_);
    DCHECK(rv);
  }
}

void ResourceBundle::LoadResources(const std::wstring& pref_locale) {
  // As a convenience, set resources_data_ to the current module.
  resources_data_ = _AtlBaseModule.GetModuleInstance();

  DCHECK(NULL == locale_resources_data_) << "locale dll already loaded";
  const FilePath& locale_path = GetLocaleFilePath(pref_locale);
  if (locale_path.value().empty()) {
    // It's possible that there are no locale dlls found, in which case we just
    // return.
    NOTREACHED();
    return;
  }

  // The dll should only have resources, not executable code.
  locale_resources_data_ = LoadLibraryEx(locale_path.value().c_str(), NULL,
                                         GetDataDllLoadFlags());
  DCHECK(locale_resources_data_ != NULL) <<
      "unable to load generated resources";
}

FilePath ResourceBundle::GetLocaleFilePath(const std::wstring& pref_locale) {
  FilePath locale_path;
  PathService::Get(app::DIR_LOCALES, &locale_path);

  const std::string app_locale = l10n_util::GetApplicationLocale(pref_locale);
  if (app_locale.empty())
    return FilePath();

  return locale_path.AppendASCII(app_locale + ".dll");
}

void ResourceBundle::LoadThemeResources() {
  DCHECK(NULL == theme_data_) << "theme dll already loaded";
  FilePath theme_data_path;
  PathService::Get(app::DIR_THEMES, &theme_data_path);
  theme_data_path = theme_data_path.AppendASCII("default.dll");

  // The dll should only have resources, not executable code.
  theme_data_ = LoadLibraryEx(theme_data_path.value().c_str(), NULL,
                              GetDataDllLoadFlags());
  DCHECK(theme_data_ != NULL) << "unable to load " << theme_data_path.value();
}

/* static */
bool ResourceBundle::LoadResourceBytes(
    DataHandle module,
    int resource_id,
    std::vector<unsigned char>* bytes) {
  void* data_ptr;
  size_t data_size;
  if (base::GetDataResourceFromModule(module, resource_id, &data_ptr,
                                      &data_size)) {
    bytes->resize(data_size);
    memcpy(&(bytes->front()), data_ptr, data_size);
    return true;
  } else {
    return false;
  }
}

HICON ResourceBundle::LoadThemeIcon(int icon_id) {
  return ::LoadIcon(theme_data_, MAKEINTRESOURCE(icon_id));
}

base::StringPiece ResourceBundle::GetRawDataResource(int resource_id) {
  void* data_ptr;
  size_t data_size;
  if (base::GetDataResourceFromModule(_AtlBaseModule.GetModuleInstance(),
                                      resource_id,
                                      &data_ptr,
                                      &data_size)) {
    return base::StringPiece(static_cast<const char*>(data_ptr), data_size);
  } else if (locale_resources_data_ &&
             base::GetDataResourceFromModule(locale_resources_data_,
                                             resource_id,
                                             &data_ptr,
                                             &data_size)) {
    return base::StringPiece(static_cast<const char*>(data_ptr), data_size);
  }
  return base::StringPiece();
}

// Loads and returns a cursor from the current module.
HCURSOR ResourceBundle::LoadCursor(int cursor_id) {
  return ::LoadCursor(_AtlBaseModule.GetModuleInstance(),
                      MAKEINTRESOURCE(cursor_id));
}

string16 ResourceBundle::GetLocalizedString(int message_id) {
  // If for some reason we were unable to load a resource dll, return an empty
  // string (better than crashing).
  if (!locale_resources_data_) {
    LOG(WARNING) << "locale resources are not loaded";
    return string16();
  }

  DCHECK(IS_INTRESOURCE(message_id));

  // Get a reference directly to the string resource.
  HINSTANCE hinstance = locale_resources_data_;
  const ATLSTRINGRESOURCEIMAGE* image = AtlGetStringResourceImage(hinstance,
                                                                  message_id);
  if (!image) {
    // Fall back on the current module (shouldn't be any strings here except
    // in unittests).
    image = AtlGetStringResourceImage(_AtlBaseModule.GetModuleInstance(),
                                      message_id);
    if (!image) {
      NOTREACHED() << "unable to find resource: " << message_id;
      return std::wstring();
    }
  }
  // Copy into a string16 and return.
  return string16(image->achString, image->nLength);
}
<commit_msg>Print a stacktrace when we can't find a string resource (on Windows).<commit_after>// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "app/resource_bundle.h"

#include <atlbase.h>

#include "app/app_paths.h"
#include "app/gfx/font.h"
#include "app/l10n_util.h"
#include "base/debug_util.h"
#include "base/file_util.h"
#include "base/logging.h"
#include "base/path_service.h"
#include "base/resource_util.h"
#include "base/string_piece.h"
#include "base/win_util.h"

namespace {

// Returns the flags that should be passed to LoadLibraryEx.
DWORD GetDataDllLoadFlags() {
  if (win_util::GetWinVersion() >= win_util::WINVERSION_VISTA)
    return LOAD_LIBRARY_AS_DATAFILE_EXCLUSIVE | LOAD_LIBRARY_AS_IMAGE_RESOURCE;

  return DONT_RESOLVE_DLL_REFERENCES;
}

}  // end anonymous namespace

ResourceBundle::~ResourceBundle() {
  FreeImages();

  if (locale_resources_data_) {
    BOOL rv = FreeLibrary(locale_resources_data_);
    DCHECK(rv);
  }
  if (theme_data_) {
    BOOL rv = FreeLibrary(theme_data_);
    DCHECK(rv);
  }
}

void ResourceBundle::LoadResources(const std::wstring& pref_locale) {
  // As a convenience, set resources_data_ to the current module.
  resources_data_ = _AtlBaseModule.GetModuleInstance();

  DCHECK(NULL == locale_resources_data_) << "locale dll already loaded";
  const FilePath& locale_path = GetLocaleFilePath(pref_locale);
  if (locale_path.value().empty()) {
    // It's possible that there are no locale dlls found, in which case we just
    // return.
    NOTREACHED();
    return;
  }

  // The dll should only have resources, not executable code.
  locale_resources_data_ = LoadLibraryEx(locale_path.value().c_str(), NULL,
                                         GetDataDllLoadFlags());
  DCHECK(locale_resources_data_ != NULL) <<
      "unable to load generated resources";
}

FilePath ResourceBundle::GetLocaleFilePath(const std::wstring& pref_locale) {
  FilePath locale_path;
  PathService::Get(app::DIR_LOCALES, &locale_path);

  const std::string app_locale = l10n_util::GetApplicationLocale(pref_locale);
  if (app_locale.empty())
    return FilePath();

  return locale_path.AppendASCII(app_locale + ".dll");
}

void ResourceBundle::LoadThemeResources() {
  DCHECK(NULL == theme_data_) << "theme dll already loaded";
  FilePath theme_data_path;
  PathService::Get(app::DIR_THEMES, &theme_data_path);
  theme_data_path = theme_data_path.AppendASCII("default.dll");

  // The dll should only have resources, not executable code.
  theme_data_ = LoadLibraryEx(theme_data_path.value().c_str(), NULL,
                              GetDataDllLoadFlags());
  DCHECK(theme_data_ != NULL) << "unable to load " << theme_data_path.value();
}

/* static */
bool ResourceBundle::LoadResourceBytes(
    DataHandle module,
    int resource_id,
    std::vector<unsigned char>* bytes) {
  void* data_ptr;
  size_t data_size;
  if (base::GetDataResourceFromModule(module, resource_id, &data_ptr,
                                      &data_size)) {
    bytes->resize(data_size);
    memcpy(&(bytes->front()), data_ptr, data_size);
    return true;
  } else {
    return false;
  }
}

HICON ResourceBundle::LoadThemeIcon(int icon_id) {
  return ::LoadIcon(theme_data_, MAKEINTRESOURCE(icon_id));
}

base::StringPiece ResourceBundle::GetRawDataResource(int resource_id) {
  void* data_ptr;
  size_t data_size;
  if (base::GetDataResourceFromModule(_AtlBaseModule.GetModuleInstance(),
                                      resource_id,
                                      &data_ptr,
                                      &data_size)) {
    return base::StringPiece(static_cast<const char*>(data_ptr), data_size);
  } else if (locale_resources_data_ &&
             base::GetDataResourceFromModule(locale_resources_data_,
                                             resource_id,
                                             &data_ptr,
                                             &data_size)) {
    return base::StringPiece(static_cast<const char*>(data_ptr), data_size);
  }
  return base::StringPiece();
}

// Loads and returns a cursor from the current module.
HCURSOR ResourceBundle::LoadCursor(int cursor_id) {
  return ::LoadCursor(_AtlBaseModule.GetModuleInstance(),
                      MAKEINTRESOURCE(cursor_id));
}

string16 ResourceBundle::GetLocalizedString(int message_id) {
  // If for some reason we were unable to load a resource dll, return an empty
  // string (better than crashing).
  if (!locale_resources_data_) {
    StackTrace().PrintBacktrace();  // See http://crbug.com/21925.
    LOG(WARNING) << "locale resources are not loaded";
    return string16();
  }

  DCHECK(IS_INTRESOURCE(message_id));

  // Get a reference directly to the string resource.
  HINSTANCE hinstance = locale_resources_data_;
  const ATLSTRINGRESOURCEIMAGE* image = AtlGetStringResourceImage(hinstance,
                                                                  message_id);
  if (!image) {
    // Fall back on the current module (shouldn't be any strings here except
    // in unittests).
    image = AtlGetStringResourceImage(_AtlBaseModule.GetModuleInstance(),
                                      message_id);
    if (!image) {
      StackTrace().PrintBacktrace();  // See http://crbug.com/21925.
      NOTREACHED() << "unable to find resource: " << message_id;
      return std::wstring();
    }
  }
  // Copy into a string16 and return.
  return string16(image->achString, image->nLength);
}
<|endoftext|>


<commit_before>#ifndef ZXTK_UTILITIES_MODULES_REGISTER_SET_INCLUDE_GUARD
#define ZXTK_UTILITIES_MODULES_REGISTER_SET_INCLUDE_GUARD

#include <zxtk/misc/zxtk_types.hpp>

namespace zxtk
{
    namespace register_set
    {
        class z80_register_set
        {
        public:
            // WARNING: THIS IS NOT THREAD SAFE. WRITING TO THIS FROM SOMETHING OTHER THAN THE CPU OR I/O IS NOT RECOMMENDED
            types::byte a() const {return st_af >> 8;}
            types::byte b() const {return st_bc >> 8;}
            types::byte d() const {return st_de >> 8;}
            types::byte h() const {return st_hl >> 8;}
            types::byte ixh() const {return st_ix >> 8;}
            types::byte iyh() const {return st_iy >> 8;}
            types::byte f() const {return st_af & 256;}
            types::byte c() const {return st_bc & 256;}
            types::byte e() const {return st_de & 256;}
            types::byte l() const {return st_hl & 256;}
            types::byte ixl() const {return st_ix & 256;}
            types::byte iyl() const {return st_iy & 256;}
            void a(types::byte n) {st_af = (st_af & 256) + (n << 8);}
            void b(types::byte n) {st_bc = (st_bc & 256) + (n << 8);}
            void d(types::byte n) {st_de = (st_de & 256) + (n << 8);}
            void h(types::byte n) {st_hl = (st_hl & 256) + (n << 8);}
            void ixh(types::byte n) {st_ix = (st_ix & 256) + (n << 8);}
            void iyh(types::byte n) {st_iy = (st_iy & 256) + (n << 8);}
            void f(types::byte n) {st_af = (st_af & 65280) + n;}
            void c(types::byte n) {st_bc = (st_bc & 65280) + n;}
            void e(types::byte n) {st_de = (st_de & 65280) + n;}
            void l(types::byte n) {st_hl = (st_hl & 65280) + n;}
            void ixl(types::byte n) {st_ix = (st_ix & 65280) + n;}
            void ixy(types::byte n) {st_iy = (st_iy & 65280) + n;}
        private:
            types::word st_af;
            types::word st_bc;
            types::word st_de;
            types::word st_hl;
            types::word st_pc;
            types::word st_ix;
            types::word st_iy;
        };
    }
}

#endif
<commit_msg>Added register set functions<commit_after>#ifndef ZXTK_UTILITIES_MODULES_REGISTER_SET_INCLUDE_GUARD
#define ZXTK_UTILITIES_MODULES_REGISTER_SET_INCLUDE_GUARD

#include <utility>
#include <zxtk/misc/zxtk_types.hpp>

namespace zxtk
{
    namespace register_set
    {
        class z80_register_set
        {
        public:
            // WARNING: THIS IS NOT THREAD SAFE. WRITING TO THIS FROM SOMETHING OTHER THAN THE CPU OR I/O IS NOT RECOMMENDED
            types::byte a() const {return st_af >> 8;}
            types::byte b() const {return st_bc >> 8;}
            types::byte d() const {return st_de >> 8;}
            types::byte h() const {return st_hl >> 8;}
            types::byte ixh() const {return st_ix >> 8;}
            types::byte iyh() const {return st_iy >> 8;}
            types::byte f() const {return st_af & 256;}
            types::byte c() const {return st_bc & 256;}
            types::byte e() const {return st_de & 256;}
            types::byte l() const {return st_hl & 256;}
            types::byte ixl() const {return st_ix & 256;}
            types::byte iyl() const {return st_iy & 256;}
            void a(types::byte n) {st_af = (st_af & 256) + (n << 8);}
            void b(types::byte n) {st_bc = (st_bc & 256) + (n << 8);}
            void d(types::byte n) {st_de = (st_de & 256) + (n << 8);}
            void h(types::byte n) {st_hl = (st_hl & 256) + (n << 8);}
            void ixh(types::byte n) {st_ix = (st_ix & 256) + (n << 8);}
            void iyh(types::byte n) {st_iy = (st_iy & 256) + (n << 8);}
            void f(types::byte n) {st_af = (st_af & 65280) + n;}
            void c(types::byte n) {st_bc = (st_bc & 65280) + n;}
            void e(types::byte n) {st_de = (st_de & 65280) + n;}
            void l(types::byte n) {st_hl = (st_hl & 65280) + n;}
            void ixl(types::byte n) {st_ix = (st_ix & 65280) + n;}
            void ixy(types::byte n) {st_iy = (st_iy & 65280) + n;}
            types::word af() const {return st_af;}
            types::word bc() const {return st_bc;}
            types::word de() const {return st_de;}
            types::word hl() const {return st_hl;}
            types::word ix() const {return st_ix;}
            types::word iy() const {return st_iy;}
            void af(types::word n) {st_af=n;}
            void bc(types::word n) {st_bc=n;}
            void de(types::word n) {st_de=n;}
            void hl(types::word n) {st_hl=n;}
            void ix(types::word n) {st_ix=n;}
            void iy(types::word n) {st_iy=n;}
            types::word pc() const {return st_pc;}
            types::word sp() const {return st_sp;}
            types::word pc(types::word n) {st_pc=n;}
            types::word sp(types::word n) {st_sp=n;}
            types::word ex_af(types::word n) {return std::exchange(st_af,n);}
            types::word ex_bc(types::word n) {return std::exchange(st_bc,n);}
            types::word ex_de(types::word n) {return std::exchange(st_de,n);}
            types::word ex_hl(types::word n) {return std::exchange(st_hl,n);}
            types::word ex_ix(types::word n) {return std::exchange(st_ix,n);}
            types::word ex_iy(types::word n) {return std::exchange(st_iy,n);}
            types::word ex_pc(types::word n) {return std::exchange(st_pc,n);}
            types::word ex_sp(types::word n) {return std::exchange(st_sp,n);}
            void ex_af_af() {std::swap(st_af,sta_af);}
            void exx() {std::swap(st_bc,sta_bc);std::swap(st_de,sta_de);std::swap(st_hl,sta_hl);}
            void ex_de_hl() {std::swap(st_de,st_hl);}
        private:
            types::word st_af;
            types::word st_bc;
            types::word st_de;
            types::word st_hl;
            types::word sta_af;
            types::word sta_bc;
            types::word sta_de;
            types::word sta_hl;
            types::word st_pc;
            types::word st_sp;
            types::word st_ix;
            types::word st_iy;
        };
    }
}

#endif
<|endoftext|>


<commit_before>//                                MFEM Example 3
//
// Compile with: make ex3
//
// Sample runs:  ex3 -m ../data/star.mesh
//               ex3 -m ../data/beam-tri.mesh -o 2
//               ex3 -m ../data/beam-tet.mesh
//               ex3 -m ../data/beam-hex.mesh
//               ex3 -m ../data/escher.mesh
//               ex3 -m ../data/fichera.mesh
//               ex3 -m ../data/fichera-q2.vtk
//               ex3 -m ../data/fichera-q3.mesh
//               ex3 -m ../data/square-disc-nurbs.mesh
//               ex3 -m ../data/beam-hex-nurbs.mesh
//               ex3 -m ../data/amr-hex.mesh
//               ex3 -m ../data/fichera-amr.mesh
//               ex3 -m ../data/star-surf.mesh -o 1
//               ex3 -m ../data/mobius-strip.mesh -f 0.1
//               ex3 -m ../data/klein-bottle.mesh -f 0.1
//
// Description:  This example code solves a simple electromagnetic diffusion
//               problem corresponding to the second order definite Maxwell
//               equation curl curl E + E = f with boundary condition
//               E x n = <given tangential field>. Here, we use a given exact
//               solution E and compute the corresponding r.h.s. f.
//               We discretize with Nedelec finite elements in 2D or 3D.
//
//               The example demonstrates the use of H(curl) finite element
//               spaces with the curl-curl and the (vector finite element) mass
//               bilinear form, as well as the computation of discretization
//               error when the exact solution is known. Static condensation is
//               also illustrated.
//
//               We recommend viewing examples 1-2 before viewing this example.

#include "mfem.hpp"
#include <fstream>
#include <iostream>

using namespace std;
using namespace mfem;

// Exact solution, E, and r.h.s., f. See below for implementation.
void E_exact(const Vector &, Vector &);
void f_exact(const Vector &, Vector &);
double freq = 1.0, kappa;
int dim;

int main(int argc, char *argv[])
{
   // 1. Parse command-line options.
   const char *mesh_file = "../data/beam-tet.mesh";
   int order = 1;
   bool static_cond = false;
   bool visualization = 1;

   OptionsParser args(argc, argv);
   args.AddOption(&mesh_file, "-m", "--mesh",
                  "Mesh file to use.");
   args.AddOption(&order, "-o", "--order",
                  "Finite element order (polynomial degree).");
   args.AddOption(&freq, "-f", "--frequency", "Set the frequency for the exact"
                  " solution.");
   args.AddOption(&static_cond, "-sc", "--static-condensation", "-no-sc",
                  "--no-static-condensation", "Enable static condensation.");
   args.AddOption(&visualization, "-vis", "--visualization", "-no-vis",
                  "--no-visualization",
                  "Enable or disable GLVis visualization.");
   args.Parse();
   if (!args.Good())
   {
      args.PrintUsage(cout);
      return 1;
   }
   args.PrintOptions(cout);
   kappa = freq * M_PI;

   // 2. Read the mesh from the given mesh file. We can handle triangular,
   //    quadrilateral, tetrahedral, hexahedral, surface and volume meshes with
   //    the same code.
   Mesh *mesh = new Mesh(mesh_file, 1, 1);
   dim = mesh->Dimension();
   int sdim = mesh->SpaceDimension();

   // 3. Refine the mesh to increase the resolution. In this example we do
   //    'ref_levels' of uniform refinement. We choose 'ref_levels' to be the
   //    largest number that gives a final mesh with no more than 50,000
   //    elements.
   {
      int ref_levels =
         (int)floor(log(50000./mesh->GetNE())/log(2.)/dim);
      for (int l = 0; l < ref_levels; l++)
      {
         mesh->UniformRefinement();
      }
   }
   mesh->ReorientTetMesh();

   // 4. Define a finite element space on the mesh. Here we use the Nedelec
   //    finite elements of the specified order.
   FiniteElementCollection *fec = new ND_FECollection(order, dim);
   FiniteElementSpace *fespace = new FiniteElementSpace(mesh, fec);
   cout << "Number of finite element unknowns: "
        << fespace->GetTrueVSize() << endl;

   // 5. Determine the list of true (i.e. conforming) essential boundary dofs.
   //    In this example, the boundary conditions are defined by marking all
   //    the boundary attributes from the mesh as essential (Dirichlet) and
   //    converting them to a list of true dofs.
   Array<int> ess_tdof_list;
   if (mesh->bdr_attributes.Size())
   {
      Array<int> ess_bdr(mesh->bdr_attributes.Max());
      ess_bdr = 1;
      fespace->GetEssentialTrueDofs(ess_bdr, ess_tdof_list);
   }

   // 6. Set up the linear form b(.) which corresponds to the right-hand side
   //    of the FEM linear system, which in this case is (f,phi_i) where f is
   //    given by the function f_exact and phi_i are the basis functions in the
   //    finite element fespace.
   VectorFunctionCoefficient f(sdim, f_exact);
   LinearForm *b = new LinearForm(fespace);
   b->AddDomainIntegrator(new VectorFEDomainLFIntegrator(f));
   b->Assemble();

   // 7. Define the solution vector x as a finite element grid function
   //    corresponding to fespace. Initialize x by projecting the exact
   //    solution. Note that only values from the boundary edges will be used
   //    when eliminating the non-homogeneous boundary condition to modify the
   //    r.h.s. vector b.
   GridFunction x(fespace);
   VectorFunctionCoefficient E(sdim, E_exact);
   x.ProjectCoefficient(E);

   // 8. Set up the bilinear form corresponding to the EM diffusion operator
   //    curl muinv curl + sigma I, by adding the curl-curl and the mass domain
   //    integrators.
   Coefficient *muinv = new ConstantCoefficient(1.0);
   Coefficient *sigma = new ConstantCoefficient(1.0);
   BilinearForm *a = new BilinearForm(fespace);
   a->AddDomainIntegrator(new CurlCurlIntegrator(*muinv));
   a->AddDomainIntegrator(new VectorFEMassIntegrator(*sigma));

   // 9. Assemble the bilinear form and the corresponding linear system,
   //    applying any necessary transformations such as: eliminating boundary
   //    conditions, applying conforming constraints for non-conforming AMR,
   //    static condensation, etc.
   if (static_cond) { a->EnableStaticCondensation(); }
   a->Assemble();

   SparseMatrix A;
   Vector B, X;
   a->FormLinearSystem(ess_tdof_list, x, *b, A, X, B);

   cout << "Size of linear system: " << A.Height() << endl;

#ifndef MFEM_USE_SUITESPARSE
   // 10. Define a simple symmetric Gauss-Seidel preconditioner and use it to
   //     solve the system Ax=b with PCG.
   GSSmoother M(A);
   PCG(A, M, B, X, 1, 500, 1e-12, 0.0);
#else
   // 10. If MFEM was compiled with SuiteSparse, use UMFPACK to solve the system.
   UMFPackSolver umf_solver;
   umf_solver.Control[UMFPACK_ORDERING] = UMFPACK_ORDERING_METIS;
   umf_solver.SetOperator(A);
   umf_solver.Mult(B, X);
#endif

   // 11. Recover the solution as a finite element grid function.
   a->RecoverFEMSolution(X, *b, x);

   // 12. Compute and print the L^2 norm of the error.
   cout << "\n|| E_h - E ||_{L^2} = " << x.ComputeL2Error(E) << '\n' << endl;

   // 13. Save the refined mesh and the solution. This output can be viewed
   //     later using GLVis: "glvis -m refined.mesh -g sol.gf".
   {
      ofstream mesh_ofs("refined.mesh");
      mesh_ofs.precision(8);
      mesh->Print(mesh_ofs);
      ofstream sol_ofs("sol.gf");
      sol_ofs.precision(8);
      x.Save(sol_ofs);
   }

   /////// TEST TEST /////////

   for (int i = 0; i < 3; i++)
   {
      cout << "Refining..." << endl;
      mesh->RandomRefinement(0.5);
      //mesh->UniformRefinement();
      cout << "Updating..." << endl;
      fespace->Update();
      x.Update();
   }
   cout << "Done." << endl;

   /////// TEST TEST /////////

   // 14. Send the solution by socket to a GLVis server.
   if (visualization)
   {
      char vishost[] = "localhost";
      int  visport   = 19916;
      socketstream sol_sock(vishost, visport);
      sol_sock.precision(8);
      sol_sock << "solution\n" << *mesh << x << flush;
   }

   // 15. Free the used memory.
   delete a;
   delete sigma;
   delete muinv;
   delete b;
   delete fespace;
   delete fec;
   delete mesh;

   return 0;
}

void E_exact(const Vector &x, Vector &E)
{
   if (dim == 3)
   {
      E(0) = sin(kappa * x(1));
      E(1) = sin(kappa * x(2));
      E(2) = sin(kappa * x(0));
   }
   else
   {
      E(0) = sin(kappa * x(1));
      E(1) = sin(kappa * x(0));
      if (x.Size() == 3) { E(2) = 0.0; }
   }
}

void f_exact(const Vector &x, Vector &f)
{
   if (dim == 3)
   {
      f(0) = (1. + kappa * kappa) * sin(kappa * x(1));
      f(1) = (1. + kappa * kappa) * sin(kappa * x(2));
      f(2) = (1. + kappa * kappa) * sin(kappa * x(0));
   }
   else
   {
      f(0) = (1. + kappa * kappa) * sin(kappa * x(1));
      f(1) = (1. + kappa * kappa) * sin(kappa * x(0));
      if (x.Size() == 3) { f(2) = 0.0; }
   }
}
<commit_msg>Ex3 was failing in autotests because apparently we can't refine a tet mesh after ReorientTetMesh anymore. This is either a "feature" or an unrelated problem so I'm disabling the test in ex3 for tetrahedra.<commit_after>//                                MFEM Example 3
//
// Compile with: make ex3
//
// Sample runs:  ex3 -m ../data/star.mesh
//               ex3 -m ../data/beam-tri.mesh -o 2
//               ex3 -m ../data/beam-tet.mesh
//               ex3 -m ../data/beam-hex.mesh
//               ex3 -m ../data/escher.mesh
//               ex3 -m ../data/fichera.mesh
//               ex3 -m ../data/fichera-q2.vtk
//               ex3 -m ../data/fichera-q3.mesh
//               ex3 -m ../data/square-disc-nurbs.mesh
//               ex3 -m ../data/beam-hex-nurbs.mesh
//               ex3 -m ../data/amr-hex.mesh
//               ex3 -m ../data/fichera-amr.mesh
//               ex3 -m ../data/star-surf.mesh -o 1
//               ex3 -m ../data/mobius-strip.mesh -f 0.1
//               ex3 -m ../data/klein-bottle.mesh -f 0.1
//
// Description:  This example code solves a simple electromagnetic diffusion
//               problem corresponding to the second order definite Maxwell
//               equation curl curl E + E = f with boundary condition
//               E x n = <given tangential field>. Here, we use a given exact
//               solution E and compute the corresponding r.h.s. f.
//               We discretize with Nedelec finite elements in 2D or 3D.
//
//               The example demonstrates the use of H(curl) finite element
//               spaces with the curl-curl and the (vector finite element) mass
//               bilinear form, as well as the computation of discretization
//               error when the exact solution is known. Static condensation is
//               also illustrated.
//
//               We recommend viewing examples 1-2 before viewing this example.

#include "mfem.hpp"
#include <fstream>
#include <iostream>

using namespace std;
using namespace mfem;

// Exact solution, E, and r.h.s., f. See below for implementation.
void E_exact(const Vector &, Vector &);
void f_exact(const Vector &, Vector &);
double freq = 1.0, kappa;
int dim;

int main(int argc, char *argv[])
{
   // 1. Parse command-line options.
   const char *mesh_file = "../data/beam-tet.mesh";
   int order = 1;
   bool static_cond = false;
   bool visualization = 1;

   OptionsParser args(argc, argv);
   args.AddOption(&mesh_file, "-m", "--mesh",
                  "Mesh file to use.");
   args.AddOption(&order, "-o", "--order",
                  "Finite element order (polynomial degree).");
   args.AddOption(&freq, "-f", "--frequency", "Set the frequency for the exact"
                  " solution.");
   args.AddOption(&static_cond, "-sc", "--static-condensation", "-no-sc",
                  "--no-static-condensation", "Enable static condensation.");
   args.AddOption(&visualization, "-vis", "--visualization", "-no-vis",
                  "--no-visualization",
                  "Enable or disable GLVis visualization.");
   args.Parse();
   if (!args.Good())
   {
      args.PrintUsage(cout);
      return 1;
   }
   args.PrintOptions(cout);
   kappa = freq * M_PI;

   // 2. Read the mesh from the given mesh file. We can handle triangular,
   //    quadrilateral, tetrahedral, hexahedral, surface and volume meshes with
   //    the same code.
   Mesh *mesh = new Mesh(mesh_file, 1, 1);
   dim = mesh->Dimension();
   int sdim = mesh->SpaceDimension();

   // 3. Refine the mesh to increase the resolution. In this example we do
   //    'ref_levels' of uniform refinement. We choose 'ref_levels' to be the
   //    largest number that gives a final mesh with no more than 50,000
   //    elements.
   {
      int ref_levels =
         (int)floor(log(50000./mesh->GetNE())/log(2.)/dim);
      for (int l = 0; l < ref_levels; l++)
      {
         mesh->UniformRefinement();
      }
   }
   mesh->ReorientTetMesh();

   // 4. Define a finite element space on the mesh. Here we use the Nedelec
   //    finite elements of the specified order.
   FiniteElementCollection *fec = new ND_FECollection(order, dim);
   FiniteElementSpace *fespace = new FiniteElementSpace(mesh, fec);
   cout << "Number of finite element unknowns: "
        << fespace->GetTrueVSize() << endl;

   // 5. Determine the list of true (i.e. conforming) essential boundary dofs.
   //    In this example, the boundary conditions are defined by marking all
   //    the boundary attributes from the mesh as essential (Dirichlet) and
   //    converting them to a list of true dofs.
   Array<int> ess_tdof_list;
   if (mesh->bdr_attributes.Size())
   {
      Array<int> ess_bdr(mesh->bdr_attributes.Max());
      ess_bdr = 1;
      fespace->GetEssentialTrueDofs(ess_bdr, ess_tdof_list);
   }

   // 6. Set up the linear form b(.) which corresponds to the right-hand side
   //    of the FEM linear system, which in this case is (f,phi_i) where f is
   //    given by the function f_exact and phi_i are the basis functions in the
   //    finite element fespace.
   VectorFunctionCoefficient f(sdim, f_exact);
   LinearForm *b = new LinearForm(fespace);
   b->AddDomainIntegrator(new VectorFEDomainLFIntegrator(f));
   b->Assemble();

   // 7. Define the solution vector x as a finite element grid function
   //    corresponding to fespace. Initialize x by projecting the exact
   //    solution. Note that only values from the boundary edges will be used
   //    when eliminating the non-homogeneous boundary condition to modify the
   //    r.h.s. vector b.
   GridFunction x(fespace);
   VectorFunctionCoefficient E(sdim, E_exact);
   x.ProjectCoefficient(E);

   // 8. Set up the bilinear form corresponding to the EM diffusion operator
   //    curl muinv curl + sigma I, by adding the curl-curl and the mass domain
   //    integrators.
   Coefficient *muinv = new ConstantCoefficient(1.0);
   Coefficient *sigma = new ConstantCoefficient(1.0);
   BilinearForm *a = new BilinearForm(fespace);
   a->AddDomainIntegrator(new CurlCurlIntegrator(*muinv));
   a->AddDomainIntegrator(new VectorFEMassIntegrator(*sigma));

   // 9. Assemble the bilinear form and the corresponding linear system,
   //    applying any necessary transformations such as: eliminating boundary
   //    conditions, applying conforming constraints for non-conforming AMR,
   //    static condensation, etc.
   if (static_cond) { a->EnableStaticCondensation(); }
   a->Assemble();

   SparseMatrix A;
   Vector B, X;
   a->FormLinearSystem(ess_tdof_list, x, *b, A, X, B);

   cout << "Size of linear system: " << A.Height() << endl;

#ifndef MFEM_USE_SUITESPARSE
   // 10. Define a simple symmetric Gauss-Seidel preconditioner and use it to
   //     solve the system Ax=b with PCG.
   GSSmoother M(A);
   PCG(A, M, B, X, 1, 500, 1e-12, 0.0);
#else
   // 10. If MFEM was compiled with SuiteSparse, use UMFPACK to solve the system.
   UMFPackSolver umf_solver;
   umf_solver.Control[UMFPACK_ORDERING] = UMFPACK_ORDERING_METIS;
   umf_solver.SetOperator(A);
   umf_solver.Mult(B, X);
#endif

   // 11. Recover the solution as a finite element grid function.
   a->RecoverFEMSolution(X, *b, x);

   // 12. Compute and print the L^2 norm of the error.
   cout << "\n|| E_h - E ||_{L^2} = " << x.ComputeL2Error(E) << '\n' << endl;

   // 13. Save the refined mesh and the solution. This output can be viewed
   //     later using GLVis: "glvis -m refined.mesh -g sol.gf".
   {
      ofstream mesh_ofs("refined.mesh");
      mesh_ofs.precision(8);
      mesh->Print(mesh_ofs);
      ofstream sol_ofs("sol.gf");
      sol_ofs.precision(8);
      x.Save(sol_ofs);
   }

   /////// TEST TEST /////////

   if (!(mesh->MeshGenerator() & 1))
   {
      for (int i = 0; i < 3; i++)
      {
         cout << "Refining..." << endl;
         mesh->RandomRefinement(0.5);
         //mesh->UniformRefinement();
         cout << "Updating..." << endl;
         fespace->Update();
         x.Update();
      }
      cout << "Done." << endl;
   }

   /////// TEST TEST /////////

   // 14. Send the solution by socket to a GLVis server.
   if (visualization)
   {
      char vishost[] = "localhost";
      int  visport   = 19916;
      socketstream sol_sock(vishost, visport);
      sol_sock.precision(8);
      sol_sock << "solution\n" << *mesh << x << flush;
   }

   // 15. Free the used memory.
   delete a;
   delete sigma;
   delete muinv;
   delete b;
   delete fespace;
   delete fec;
   delete mesh;

   return 0;
}

void E_exact(const Vector &x, Vector &E)
{
   if (dim == 3)
   {
      E(0) = sin(kappa * x(1));
      E(1) = sin(kappa * x(2));
      E(2) = sin(kappa * x(0));
   }
   else
   {
      E(0) = sin(kappa * x(1));
      E(1) = sin(kappa * x(0));
      if (x.Size() == 3) { E(2) = 0.0; }
   }
}

void f_exact(const Vector &x, Vector &f)
{
   if (dim == 3)
   {
      f(0) = (1. + kappa * kappa) * sin(kappa * x(1));
      f(1) = (1. + kappa * kappa) * sin(kappa * x(2));
      f(2) = (1. + kappa * kappa) * sin(kappa * x(0));
   }
   else
   {
      f(0) = (1. + kappa * kappa) * sin(kappa * x(1));
      f(1) = (1. + kappa * kappa) * sin(kappa * x(0));
      if (x.Size() == 3) { f(2) = 0.0; }
   }
}
<|endoftext|>


<commit_before>#include "improc/Filter.hpp"
#include "improc/Morphology.hpp"
#include "io/PgmIO.hpp"
#include "io/PngIO.hpp"
#include "matrix/Statistics.hpp"
#include <cstring>
#include <iostream>
#include <memory>
#include <string>
#include <vector>

using namespace sipl;

size_t start_x, start_y, end_x, end_y;
int32_t img_start, img_count;
std::string format;

void parse_commandline(char** argv);

std::vector<std::string> generate_filenames(const std::string& format,
                                            int32_t start,
                                            int32_t count);

std::vector<MatrixXb> read_video_dir(const std::vector<std::string>& filenames);

std::vector<Vector2i> bresenham(const Vector2i& p1, const Vector2i& p2);

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

    // Read in PNG's, convert to grayscale
    auto filenames = generate_filenames(format, img_start, img_count);
    auto grays = read_video_dir(filenames);

    // Compute average img
    auto avg = average(grays);

    // Compute sagittal view
    auto points = bresenham({start_x, start_y}, {end_x, end_y});
    MatrixXb slice_img(grays.size() * 2, points.size());
    for (size_t i = 0; i < grays.size(); ++i) {

        // Subtract background
        auto diff = math::abs(grays[i] - avg).clip(0, 255).as_type<uint8_t>();

        // Threshold away low 10%
        auto thresh = threshold_binary(diff, uint8_t(0.1 * 255));
        for (size_t p = 0; p < points.size(); ++p) {
            slice_img(2 * i, p) = thresh(points[p][1], points[p][0]);
            slice_img(2 * i + 1, p) = thresh(points[p][1], points[p][0]);
        }
    }

    // Median blur
    auto median_ksize = int32_t(0.02 * points.size());
    if (median_ksize % 2 == 0) {
        median_ksize += 1;
    }
    std::cout << "median filter size: " << median_ksize << std::endl;
    slice_img = median_filter(slice_img, median_ksize, median_ksize);

    // Dilate by square
    auto morph_ksize = int32_t(0.04 * points.size());
    slice_img = morphology::dilate(
        slice_img, morphology::kernels::rectangle(morph_ksize, morph_ksize));

    PgmIO::write(slice_img, "reslice.pgm");
}

void parse_commandline(char** argv)
{
    start_x = std::stoul(argv[1]);
    start_y = std::stoul(argv[2]);
    end_x = std::stoul(argv[3]);
    end_y = std::stoul(argv[4]);
    format = std::string(argv[5]);
    img_start = std::stoi(argv[6]);
    img_count = std::stoi(argv[7]);
}

std::vector<std::string> generate_filenames(const std::string& format,
                                            int32_t start,
                                            int32_t count)
{
    std::vector<std::string> filenames;
    for (int32_t i = start; i <= count; ++i) {
        // Code taken from: http://stackoverflow.com/a/26221725
        // + 1 for null terminator
        size_t size = std::snprintf(nullptr, 0, format.c_str(), i) + 1;
        auto buf = std::make_unique<char[]>(size);
        std::snprintf(buf.get(), size, format.c_str(), i);
        filenames.emplace_back(buf.get(), buf.get() + size - 1);
    }

    return filenames;
}

std::vector<MatrixXb> read_video_dir(const std::vector<std::string>& filenames)
{
    std::vector<MatrixXb> gray_pngs;
    gray_pngs.reserve(filenames.size());
    for (const auto& f : filenames) {
        auto color = PngIO::read(f);
        gray_pngs.push_back(color_to_grayscale(color));
    }

    return gray_pngs;
}

// Implementation taken from:
// https://www.cs.unm.edu/~angel/BOOK/INTERACTIVE_COMPUTER_GRAPHICS/FOURTH_EDITION/PROGRAMS/bresenham.c
std::vector<Vector2i> bresenham(const Vector2i& p1, const Vector2i& p2)
{
    std::vector<Vector2i> points;
    int32_t dx, dy, i, e;
    int32_t incx, incy, inc1, inc2;
    int32_t x, y;

    dx = p2[0] - p1[0];
    dy = p2[1] - p1[1];

    if (dx < 0) {
        dx = -dx;
    }
    if (dy < 0) {
        dy = -dy;
    }
    incx = 1;
    if (p2[0] < p1[0]) {
        incx = -1;
    }
    incy = 1;
    if (p2[1] < p1[1]) {
        incy = -1;
    }
    x = p1[0];
    y = p1[1];

    if (dx > dy) {
        points.push_back({x, y});
        e = 2 * dy - dx;
        inc1 = 2 * (dy - dx);
        inc2 = 2 * dy;
        for (i = 0; i < dx; i++) {
            if (e >= 0) {
                y += incy;
                e += inc1;
            } else {
                e += inc2;
            }
            x += incx;
            points.push_back({x, y});
        }
    } else {
        points.push_back({x, y});
        e = 2 * dx - dy;
        inc1 = 2 * (dx - dy);
        inc2 = 2 * dx;
        for (i = 0; i < dy; i++) {
            if (e >= 0) {
                x += incx;
                e += inc1;
            } else {
                e += inc2;
            }
            y += incy;
            points.push_back({x, y});
        }
    }

    return points;
}
<commit_msg>Final version of car-counting code<commit_after>#include "Util.hpp"
#include "improc/Filter.hpp"
#include "improc/Label.hpp"
#include "improc/Morphology.hpp"
#include "io/PgmIO.hpp"
#include "io/PngIO.hpp"
#include "matrix/Statistics.hpp"
#include <cstring>
#include <iostream>
#include <memory>
#include <string>
#include <vector>

size_t start_x, start_y, end_x, end_y;
int32_t img_start, img_count;
std::string format;

void parse_commandline(char** argv);

std::vector<std::string> generate_filenames(const std::string& format,
                                            int32_t start,
                                            int32_t count);

std::vector<sipl::MatrixXb> read_video_dir(
    const std::vector<std::string>& filenames);

std::vector<sipl::Vector2i> bresenham(const sipl::Vector2i& p1,
                                      const sipl::Vector2i& p2);

double average_mass(const std::vector<sipl::Component>& cs);

constexpr uint8_t THRESH_VAL = uint8_t(0.0875 * 255);
constexpr double MORPH_KERNEL_SIZE_PERC = 0.03;
constexpr double REMOVE_BLOB_MASS_PERC = 0.2;
constexpr double SPLIT_BLOB_FACTOR = 1.5;
constexpr double BLOB_MERGE_FACTOR = 0.02;

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

    // Read in PNG's, convert to grayscale
    auto filenames = generate_filenames(format, img_start, img_count);
    auto grays = read_video_dir(filenames);

    // Compute average img
    auto avg = sipl::average(grays);

    // Compute sagittal view
    auto points = bresenham({start_x, start_y}, {end_x, end_y});
    sipl::MatrixXb slice_img(grays.size() * 2, points.size());
    for (size_t i = 0; i < grays.size(); ++i) {

        // Subtract background
        auto diff =
            sipl::math::abs(grays[i] - avg).clip(0, 255).as_type<uint8_t>();

        // Threshold away low 10%
        auto thresh_img = sipl::threshold_binary(diff, THRESH_VAL);
        for (size_t p = 0; p < points.size(); ++p) {
            slice_img(2 * i, p) = thresh_img(points[p][1], points[p][0]);
            slice_img(2 * i + 1, p) = thresh_img(points[p][1], points[p][0]);
        }
    }
    sipl::PgmIO::write(slice_img, "01_sub_bg_thresh.pgm");

    // Median blur
    auto median_ksize = int32_t(0.02 * points.size());
    if (median_ksize % 2 == 0) {
        median_ksize += 1;
    }
    std::cout << "median filter size: " << median_ksize << std::endl;
    slice_img = sipl::median_filter(slice_img, median_ksize, median_ksize);
    sipl::PgmIO::write(slice_img, "02_med_filter.pgm");

    // Dilate by square
    auto morph_ksize = int32_t(MORPH_KERNEL_SIZE_PERC * points.size());
    std::cout << "morphology kernel size: " << morph_ksize << std::endl;
    slice_img = sipl::morphology::dilate(
        slice_img,
        sipl::morphology::kernels::rectangle(morph_ksize, morph_ksize));
    sipl::PgmIO::write(slice_img, "03_morph.pgm");

    // Find connected components
    auto components =
        sipl::connected_components(slice_img, sipl::Connectivity::N8);
    std::cout << "# raw components: " << components.size() << std::endl;
    std::cout << "avg mass (all blobs): " << sipl::average_mass(components)
              << std::endl;

    // Filter any blobs < REMOVE_BLOB_MASS_PERC% of the avg mass
    double avg_mass = sipl::average_mass(components);
    auto it = std::partition(
        std::begin(components), std::end(components), [avg_mass](auto c) {
            return c.mass >= REMOVE_BLOB_MASS_PERC * avg_mass;
        });
    std::vector<sipl::Component> large_blobs(std::begin(components), it);
    std::vector<sipl::Component> small_blobs(it, std::end(components));

    // Draw over small blobs and remove them from image
    for (const auto& blob : small_blobs) {
        for (const auto& i : blob.indices) {
            slice_img(i[0], i[1]) = 0;
        }
    }
    sipl::PgmIO::write(slice_img, "04_remove_small_blobs.pgm");

    /*
    // Do another dilate
    slice_img = sipl::morphology::close(
        slice_img,
        sipl::morphology::kernels::rectangle(morph_ksize, morph_ksize));
    sipl::PgmIO::write(slice_img, "05_morph_2.pgm");

    // Get new connected components
    components = sipl::connected_components(slice_img, sipl::Connectivity::N8);
    */

    // Recalculate avg_mass
    auto total_mass = sipl::total_mass(large_blobs);
    avg_mass = sipl::average_mass(large_blobs);
    std::cout << "tot mass: " << total_mass << std::endl;
    std::cout << "avg mass: " << avg_mass << std::endl;
    std::cout << "div:      " << double(total_mass) / avg_mass << std::endl;

    std::cout << "# of components (small blobs removed): " << large_blobs.size()
              << std::endl;
    for (size_t i = 0; i < large_blobs.size(); ++i) {
        std::cout << i + 1 << "\tmass: " << large_blobs[i].mass
                  << "\tcom: " << large_blobs[i].center_of_mass << std::endl;
    }

    // Get a new count
    size_t car_count = large_blobs.size();
    for (const auto& c : large_blobs) {
        if (c.mass > SPLIT_BLOB_FACTOR * avg_mass) {
            car_count++;
        }
    }
    std::cout << "new car count: " << car_count << std::endl;
}

void parse_commandline(char** argv)
{
    start_x = std::stoul(argv[1]);
    start_y = std::stoul(argv[2]);
    end_x = std::stoul(argv[3]);
    end_y = std::stoul(argv[4]);
    format = std::string(argv[5]);
    img_start = std::stoi(argv[6]);
    img_count = std::stoi(argv[7]);
}

std::vector<std::string> generate_filenames(const std::string& format,
                                            int32_t start,
                                            int32_t count)
{
    std::vector<std::string> filenames;
    for (int32_t i = start; i <= count; ++i) {
        // Code taken from: http://stackoverflow.com/a/26221725
        // + 1 for null terminator
        size_t size = std::snprintf(nullptr, 0, format.c_str(), i) + 1;
        auto buf = std::make_unique<char[]>(size);
        std::snprintf(buf.get(), size, format.c_str(), i);
        filenames.emplace_back(buf.get(), buf.get() + size - 1);
    }

    return filenames;
}

std::vector<sipl::MatrixXb> read_video_dir(
    const std::vector<std::string>& filenames)
{
    std::vector<sipl::MatrixXb> gray_pngs;
    gray_pngs.reserve(filenames.size());
    for (const auto& f : filenames) {
        auto color = sipl::PngIO::read(f);
        gray_pngs.push_back(color_to_grayscale(color));
    }

    return gray_pngs;
}

// Implementation taken from:
// https://www.cs.unm.edu/~angel/BOOK/INTERACTIVE_COMPUTER_GRAPHICS/FOURTH_EDITION/PROGRAMS/bresenham.c
std::vector<sipl::Vector2i> bresenham(const sipl::Vector2i& p1,
                                      const sipl::Vector2i& p2)
{
    std::vector<sipl::Vector2i> points;
    int32_t dx, dy, i, e;
    int32_t incx, incy, inc1, inc2;
    int32_t x, y;

    dx = p2[0] - p1[0];
    dy = p2[1] - p1[1];

    if (dx < 0) {
        dx = -dx;
    }
    if (dy < 0) {
        dy = -dy;
    }
    incx = 1;
    if (p2[0] < p1[0]) {
        incx = -1;
    }
    incy = 1;
    if (p2[1] < p1[1]) {
        incy = -1;
    }
    x = p1[0];
    y = p1[1];

    if (dx > dy) {
        points.push_back({x, y});
        e = 2 * dy - dx;
        inc1 = 2 * (dy - dx);
        inc2 = 2 * dy;
        for (i = 0; i < dx; i++) {
            if (e >= 0) {
                y += incy;
                e += inc1;
            } else {
                e += inc2;
            }
            x += incx;
            points.push_back({x, y});
        }
    } else {
        points.push_back({x, y});
        e = 2 * dx - dy;
        inc1 = 2 * (dx - dy);
        inc2 = 2 * dx;
        for (i = 0; i < dy; i++) {
            if (e >= 0) {
                x += incx;
                e += inc1;
            } else {
                e += inc2;
            }
            y += incy;
            points.push_back({x, y});
        }
    }

    return points;
}
<|endoftext|>


<commit_before>/*************************************************************************
 *
 *  $RCSfile: SlideTransitionPanel.hxx,v $
 *
 *  $Revision: 1.4 $
 *
 *  last change: $Author: kz $ $Date: 2005-07-14 10:27:21 $
 *
 *  The Contents of this file are made available subject to the terms of
 *  either of the following licenses
 *
 *         - GNU Lesser General Public License Version 2.1
 *         - Sun Industry Standards Source License Version 1.1
 *
 *  Sun Microsystems Inc., October, 2000
 *
 *  GNU Lesser General Public License Version 2.1
 *  =============================================
 *  Copyright 2000 by Sun Microsystems, Inc.
 *  901 San Antonio Road, Palo Alto, CA 94303, USA
 *
 *  This library is free software; you can redistribute it and/or
 *  modify it under the terms of the GNU Lesser General Public
 *  License version 2.1, as published by the Free Software Foundation.
 *
 *  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., 59 Temple Place, Suite 330, Boston,
 *  MA  02111-1307  USA
 *
 *
 *  Sun Industry Standards Source License Version 1.1
 *  =================================================
 *  The contents of this file are subject to the Sun Industry Standards
 *  Source License Version 1.1 (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.openoffice.org/license.html.
 *
 *  Software provided under this License is provided on an "AS IS" basis,
 *  WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING,
 *  WITHOUT LIMITATION, WARRANTIES THAT THE SOFTWARE IS FREE OF DEFECTS,
 *  MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE, OR NON-INFRINGING.
 *  See the License for the specific provisions governing your rights and
 *  obligations concerning the Software.
 *
 *  The Initial Developer of the Original Code is: Sun Microsystems, Inc.
 *
 *  Copyright: 2000 by Sun Microsystems, Inc.
 *
 *  All Rights Reserved.
 *
 *  Contributor(s): _______________________________________
 *
 *
 ************************************************************************/
#ifndef SD_TOOLPANEL_CONTROLS_SLIDE_TRANSITION_PANEL_HXX
#define SD_TOOLPANEL_CONTROLS_SLIDE_TRANSITION_PANEL_HXX

#include "taskpane/SubToolPanel.hxx"

namespace sd {
class ViewShellBase;
}

namespace sd { namespace toolpanel {
class ControlFactory;
class TreeNode;
} }

namespace sd { namespace toolpanel { namespace controls {

class SlideTransitionPanel
    : public SubToolPanel
{
public:
    SlideTransitionPanel (
        TreeNode* pParent,
        ViewShellBase& rBase);
    virtual ~SlideTransitionPanel (void);

    static std::auto_ptr<ControlFactory> CreateControlFactory (ViewShellBase& rBase);

    virtual Size GetPreferredSize (void);
    virtual sal_Int32 GetPreferredWidth (sal_Int32 nHeigh);
    virtual sal_Int32 GetPreferredHeight (sal_Int32 nWidth);
    virtual ::Window* GetWindow (void);
    virtual bool IsResizable (void);
    virtual bool IsExpandable (void) const;

    virtual ::com::sun::star::uno::Reference<
        ::com::sun::star::accessibility::XAccessible > CreateAccessibleObject (
            const ::com::sun::star::uno::Reference<
            ::com::sun::star::accessibility::XAccessible>& rxParent);

private:
    Size maPreferredSize;
    ::Window* mpWrappedControl;
};

} } } // end of namespace ::sd::toolpanel::controls

#endif
<commit_msg>INTEGRATION: CWS ooo19126 (1.4.66); FILE MERGED 2005/09/05 13:25:04 rt 1.4.66.1: #i54170# Change license header: remove SISSL<commit_after>/*************************************************************************
 *
 *  OpenOffice.org - a multi-platform office productivity suite
 *
 *  $RCSfile: SlideTransitionPanel.hxx,v $
 *
 *  $Revision: 1.5 $
 *
 *  last change: $Author: rt $ $Date: 2005-09-09 06:43:46 $
 *
 *  The Contents of this file are made available subject to
 *  the terms of GNU Lesser General Public License Version 2.1.
 *
 *
 *    GNU Lesser General Public License Version 2.1
 *    =============================================
 *    Copyright 2005 by Sun Microsystems, Inc.
 *    901 San Antonio Road, Palo Alto, CA 94303, USA
 *
 *    This library is free software; you can redistribute it and/or
 *    modify it under the terms of the GNU Lesser General Public
 *    License version 2.1, as published by the Free Software Foundation.
 *
 *    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., 59 Temple Place, Suite 330, Boston,
 *    MA  02111-1307  USA
 *
 ************************************************************************/
#ifndef SD_TOOLPANEL_CONTROLS_SLIDE_TRANSITION_PANEL_HXX
#define SD_TOOLPANEL_CONTROLS_SLIDE_TRANSITION_PANEL_HXX

#include "taskpane/SubToolPanel.hxx"

namespace sd {
class ViewShellBase;
}

namespace sd { namespace toolpanel {
class ControlFactory;
class TreeNode;
} }

namespace sd { namespace toolpanel { namespace controls {

class SlideTransitionPanel
    : public SubToolPanel
{
public:
    SlideTransitionPanel (
        TreeNode* pParent,
        ViewShellBase& rBase);
    virtual ~SlideTransitionPanel (void);

    static std::auto_ptr<ControlFactory> CreateControlFactory (ViewShellBase& rBase);

    virtual Size GetPreferredSize (void);
    virtual sal_Int32 GetPreferredWidth (sal_Int32 nHeigh);
    virtual sal_Int32 GetPreferredHeight (sal_Int32 nWidth);
    virtual ::Window* GetWindow (void);
    virtual bool IsResizable (void);
    virtual bool IsExpandable (void) const;

    virtual ::com::sun::star::uno::Reference<
        ::com::sun::star::accessibility::XAccessible > CreateAccessibleObject (
            const ::com::sun::star::uno::Reference<
            ::com::sun::star::accessibility::XAccessible>& rxParent);

private:
    Size maPreferredSize;
    ::Window* mpWrappedControl;
};

} } } // end of namespace ::sd::toolpanel::controls

#endif
<|endoftext|>