<commit_before>/*
 * Copyright (C) 2013 Google Inc. All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are
 * met:
 *
 *     * Redistributions of source code must retain the above copyright
 * notice, this list of conditions and the following disclaimer.
 *     * Redistributions in binary form must reproduce the above
 * copyright notice, this list of conditions and the following disclaimer
 * in the documentation and/or other materials provided with the
 * distribution.
 *     * Neither the name of Google Inc. nor the names of its
 * contributors may be used to endorse or promote products derived from
 * this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

#include "config.h"
#include "modules/mediasource/MediaSourceBase.h"

#include "bindings/v8/ExceptionState.h"
#include "bindings/v8/ExceptionStatePlaceholder.h"
#include "core/dom/ExceptionCode.h"
#include "core/events/Event.h"
#include "core/events/GenericEventQueue.h"
#include "core/html/TimeRanges.h"
#include "modules/mediasource/MediaSourceRegistry.h"
#include "platform/Logging.h"
#include "platform/TraceEvent.h"
#include "public/platform/WebMediaSource.h"
#include "public/platform/WebSourceBuffer.h"
#include "wtf/text/WTFString.h"

using blink::WebMediaSource;
using blink::WebSourceBuffer;

namespace WebCore {

MediaSourceBase::MediaSourceBase(ExecutionContext* context)
    : ActiveDOMObject(context)
    , m_readyState(closedKeyword())
    , m_asyncEventQueue(GenericEventQueue::create(this))
    , m_attachedElement(0)
{
}

MediaSourceBase::~MediaSourceBase()
{
}

const AtomicString& MediaSourceBase::openKeyword()
{
    DEFINE_STATIC_LOCAL(const AtomicString, open, ("open", AtomicString::ConstructFromLiteral));
    return open;
}

const AtomicString& MediaSourceBase::closedKeyword()
{
    DEFINE_STATIC_LOCAL(const AtomicString, closed, ("closed", AtomicString::ConstructFromLiteral));
    return closed;
}

const AtomicString& MediaSourceBase::endedKeyword()
{
    DEFINE_STATIC_LOCAL(const AtomicString, ended, ("ended", AtomicString::ConstructFromLiteral));
    return ended;
}

void MediaSourceBase::setWebMediaSourceAndOpen(PassOwnPtr<WebMediaSource> webMediaSource)
{
    TRACE_EVENT_ASYNC_END0("media", "MediaSourceBase::attachToElement", this);
    ASSERT(webMediaSource);
    ASSERT(!m_webMediaSource);
    ASSERT(m_attachedElement);
    m_webMediaSource = webMediaSource;
    setReadyState(openKeyword());
}

void MediaSourceBase::addedToRegistry()
{
    setPendingActivity(this);
}

void MediaSourceBase::removedFromRegistry()
{
    unsetPendingActivity(this);
}

double MediaSourceBase::duration() const
{
    return isClosed() ? std::numeric_limits<float>::quiet_NaN() : m_webMediaSource->duration();
}

PassRefPtr<TimeRanges> MediaSourceBase::buffered() const
{
    // Implements MediaSource algorithm for HTMLMediaElement.buffered.
    // https://dvcs.w3.org/hg/html-media/raw-file/default/media-source/media-source.html#htmlmediaelement-extensions
    Vector<RefPtr<TimeRanges> > ranges = activeRanges();

    // 1. If activeSourceBuffers.length equals 0 then return an empty TimeRanges object and abort these steps.
    if (ranges.isEmpty())
        return TimeRanges::create();

    // 2. Let active ranges be the ranges returned by buffered for each SourceBuffer object in activeSourceBuffers.
    // 3. Let highest end time be the largest range end time in the active ranges.
    double highestEndTime = -1;
    for (size_t i = 0; i < ranges.size(); ++i) {
        unsigned length = ranges[i]->length();
        if (length)
            highestEndTime = std::max(highestEndTime, ranges[i]->end(length - 1, ASSERT_NO_EXCEPTION));
    }

    // Return an empty range if all ranges are empty.
    if (highestEndTime < 0)
        return TimeRanges::create();

    // 4. Let intersection ranges equal a TimeRange object containing a single range from 0 to highest end time.
    RefPtr<TimeRanges> intersectionRanges = TimeRanges::create(0, highestEndTime);

    // 5. For each SourceBuffer object in activeSourceBuffers run the following steps:
    bool ended = readyState() == endedKeyword();
    for (size_t i = 0; i < ranges.size(); ++i) {
        // 5.1 Let source ranges equal the ranges returned by the buffered attribute on the current SourceBuffer.
        TimeRanges* sourceRanges = ranges[i].get();

        // 5.2 If readyState is "ended", then set the end time on the last range in source ranges to highest end time.
        if (ended && sourceRanges->length())
            sourceRanges->add(sourceRanges->start(sourceRanges->length() - 1, ASSERT_NO_EXCEPTION), highestEndTime);

        // 5.3 Let new intersection ranges equal the the intersection between the intersection ranges and the source ranges.
        // 5.4 Replace the ranges in intersection ranges with the new intersection ranges.
        intersectionRanges->intersectWith(sourceRanges);
    }

    return intersectionRanges.release();
}

void MediaSourceBase::setDuration(double duration, ExceptionState& exceptionState)
{
    if (duration < 0.0 || std::isnan(duration)) {
        exceptionState.throwUninformativeAndGenericDOMException(InvalidAccessError);
        return;
    }
    if (!isOpen()) {
        exceptionState.throwUninformativeAndGenericDOMException(InvalidStateError);
        return;
    }

    // Synchronously process duration change algorithm to enforce any required
    // seek is started prior to returning.
    m_attachedElement->durationChanged(duration);
    m_webMediaSource->setDuration(duration);
}

void MediaSourceBase::setReadyState(const AtomicString& state)
{
    ASSERT(state == openKeyword() || state == closedKeyword() || state == endedKeyword());

    AtomicString oldState = readyState();
    WTF_LOG(Media, "MediaSourceBase::setReadyState() %p : %s -> %s", this, oldState.string().ascii().data(), state.string().ascii().data());

    if (state == closedKeyword()) {
        m_webMediaSource.clear();
        m_attachedElement = 0;
    }

    if (oldState == state)
        return;

    m_readyState = state;

    onReadyStateChange(oldState, state);
}

void MediaSourceBase::endOfStream(const AtomicString& error, ExceptionState& exceptionState)
{
    DEFINE_STATIC_LOCAL(const AtomicString, network, ("network", AtomicString::ConstructFromLiteral));
    DEFINE_STATIC_LOCAL(const AtomicString, decode, ("decode", AtomicString::ConstructFromLiteral));

    // 3.1 http://dvcs.w3.org/hg/html-media/raw-file/tip/media-source/media-source.html#dom-endofstream
    // 1. If the readyState attribute is not in the "open" state then throw an
    // InvalidStateError exception and abort these steps.
    if (!isOpen()) {
        exceptionState.throwUninformativeAndGenericDOMException(InvalidStateError);
        return;
    }

    WebMediaSource::EndOfStreamStatus eosStatus = WebMediaSource::EndOfStreamStatusNoError;

    if (error.isNull() || error.isEmpty()) {
        eosStatus = WebMediaSource::EndOfStreamStatusNoError;
    } else if (error == network) {
        eosStatus = WebMediaSource::EndOfStreamStatusNetworkError;
    } else if (error == decode) {
        eosStatus = WebMediaSource::EndOfStreamStatusDecodeError;
    } else {
        exceptionState.throwUninformativeAndGenericDOMException(InvalidAccessError);
        return;
    }

    // 2. Change the readyState attribute value to "ended".
    setReadyState(endedKeyword());
    m_webMediaSource->markEndOfStream(eosStatus);
}

bool MediaSourceBase::isOpen() const
{
    return readyState() == openKeyword();
}

bool MediaSourceBase::isClosed() const
{
    return readyState() == closedKeyword();
}

void MediaSourceBase::close()
{
    setReadyState(closedKeyword());
}

bool MediaSourceBase::attachToElement(HTMLMediaElement* element)
{
    if (m_attachedElement)
        return false;

    ASSERT(isClosed());

    TRACE_EVENT_ASYNC_BEGIN0("media", "MediaSourceBase::attachToElement", this);
    m_attachedElement = element;
    return true;
}

void MediaSourceBase::openIfInEndedState()
{
    if (m_readyState != endedKeyword())
        return;

    setReadyState(openKeyword());
    m_webMediaSource->unmarkEndOfStream();
}

bool MediaSourceBase::hasPendingActivity() const
{
    return m_webMediaSource || m_asyncEventQueue->hasPendingEvents()
        || ActiveDOMObject::hasPendingActivity();
}

void MediaSourceBase::stop()
{
    m_asyncEventQueue->close();
    if (!isClosed())
        setReadyState(closedKeyword());
    m_webMediaSource.clear();
}

PassOwnPtr<WebSourceBuffer> MediaSourceBase::createWebSourceBuffer(const String& type, const Vector<String>& codecs, ExceptionState& exceptionState)
{
    WebSourceBuffer* webSourceBuffer = 0;
    switch (m_webMediaSource->addSourceBuffer(type, codecs, &webSourceBuffer)) {
    case WebMediaSource::AddStatusOk:
        return adoptPtr(webSourceBuffer);
    case WebMediaSource::AddStatusNotSupported:
        ASSERT(!webSourceBuffer);
        // 2.2 https://dvcs.w3.org/hg/html-media/raw-file/default/media-source/media-source.html#widl-MediaSource-addSourceBuffer-SourceBuffer-DOMString-type
        // Step 2: If type contains a MIME type ... that is not supported with the types
        // specified for the other SourceBuffer objects in sourceBuffers, then throw
        // a NotSupportedError exception and abort these steps.
        exceptionState.throwUninformativeAndGenericDOMException(NotSupportedError);
        return nullptr;
    case WebMediaSource::AddStatusReachedIdLimit:
        ASSERT(!webSourceBuffer);
        // 2.2 https://dvcs.w3.org/hg/html-media/raw-file/default/media-source/media-source.html#widl-MediaSource-addSourceBuffer-SourceBuffer-DOMString-type
        // Step 3: If the user agent can't handle any more SourceBuffer objects then throw
        // a QuotaExceededError exception and abort these steps.
        exceptionState.throwUninformativeAndGenericDOMException(QuotaExceededError);
        return nullptr;
    }

    ASSERT_NOT_REACHED();
    return nullptr;
}

void MediaSourceBase::scheduleEvent(const AtomicString& eventName)
{
    ASSERT(m_asyncEventQueue);

    RefPtr<Event> event = Event::create(eventName);
    event->setTarget(this);

    m_asyncEventQueue->enqueueEvent(event.release());
}

ExecutionContext* MediaSourceBase::executionContext() const
{
    return ActiveDOMObject::executionContext();
}

URLRegistry& MediaSourceBase::registry() const
{
    return MediaSourceRegistry::registry();
}

}
<commit_msg>Include m_attachedElement in MediaSourceBase::hasPendingActivity() condition.<commit_after>/*
 * Copyright (C) 2013 Google Inc. All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are
 * met:
 *
 *     * Redistributions of source code must retain the above copyright
 * notice, this list of conditions and the following disclaimer.
 *     * Redistributions in binary form must reproduce the above
 * copyright notice, this list of conditions and the following disclaimer
 * in the documentation and/or other materials provided with the
 * distribution.
 *     * Neither the name of Google Inc. nor the names of its
 * contributors may be used to endorse or promote products derived from
 * this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

#include "config.h"
#include "modules/mediasource/MediaSourceBase.h"

#include "bindings/v8/ExceptionState.h"
#include "bindings/v8/ExceptionStatePlaceholder.h"
#include "core/dom/ExceptionCode.h"
#include "core/events/Event.h"
#include "core/events/GenericEventQueue.h"
#include "core/html/TimeRanges.h"
#include "modules/mediasource/MediaSourceRegistry.h"
#include "platform/Logging.h"
#include "platform/TraceEvent.h"
#include "public/platform/WebMediaSource.h"
#include "public/platform/WebSourceBuffer.h"
#include "wtf/text/WTFString.h"

using blink::WebMediaSource;
using blink::WebSourceBuffer;

namespace WebCore {

MediaSourceBase::MediaSourceBase(ExecutionContext* context)
    : ActiveDOMObject(context)
    , m_readyState(closedKeyword())
    , m_asyncEventQueue(GenericEventQueue::create(this))
    , m_attachedElement(0)
{
}

MediaSourceBase::~MediaSourceBase()
{
}

const AtomicString& MediaSourceBase::openKeyword()
{
    DEFINE_STATIC_LOCAL(const AtomicString, open, ("open", AtomicString::ConstructFromLiteral));
    return open;
}

const AtomicString& MediaSourceBase::closedKeyword()
{
    DEFINE_STATIC_LOCAL(const AtomicString, closed, ("closed", AtomicString::ConstructFromLiteral));
    return closed;
}

const AtomicString& MediaSourceBase::endedKeyword()
{
    DEFINE_STATIC_LOCAL(const AtomicString, ended, ("ended", AtomicString::ConstructFromLiteral));
    return ended;
}

void MediaSourceBase::setWebMediaSourceAndOpen(PassOwnPtr<WebMediaSource> webMediaSource)
{
    TRACE_EVENT_ASYNC_END0("media", "MediaSourceBase::attachToElement", this);
    ASSERT(webMediaSource);
    ASSERT(!m_webMediaSource);
    ASSERT(m_attachedElement);
    m_webMediaSource = webMediaSource;
    setReadyState(openKeyword());
}

void MediaSourceBase::addedToRegistry()
{
    setPendingActivity(this);
}

void MediaSourceBase::removedFromRegistry()
{
    unsetPendingActivity(this);
}

double MediaSourceBase::duration() const
{
    return isClosed() ? std::numeric_limits<float>::quiet_NaN() : m_webMediaSource->duration();
}

PassRefPtr<TimeRanges> MediaSourceBase::buffered() const
{
    // Implements MediaSource algorithm for HTMLMediaElement.buffered.
    // https://dvcs.w3.org/hg/html-media/raw-file/default/media-source/media-source.html#htmlmediaelement-extensions
    Vector<RefPtr<TimeRanges> > ranges = activeRanges();

    // 1. If activeSourceBuffers.length equals 0 then return an empty TimeRanges object and abort these steps.
    if (ranges.isEmpty())
        return TimeRanges::create();

    // 2. Let active ranges be the ranges returned by buffered for each SourceBuffer object in activeSourceBuffers.
    // 3. Let highest end time be the largest range end time in the active ranges.
    double highestEndTime = -1;
    for (size_t i = 0; i < ranges.size(); ++i) {
        unsigned length = ranges[i]->length();
        if (length)
            highestEndTime = std::max(highestEndTime, ranges[i]->end(length - 1, ASSERT_NO_EXCEPTION));
    }

    // Return an empty range if all ranges are empty.
    if (highestEndTime < 0)
        return TimeRanges::create();

    // 4. Let intersection ranges equal a TimeRange object containing a single range from 0 to highest end time.
    RefPtr<TimeRanges> intersectionRanges = TimeRanges::create(0, highestEndTime);

    // 5. For each SourceBuffer object in activeSourceBuffers run the following steps:
    bool ended = readyState() == endedKeyword();
    for (size_t i = 0; i < ranges.size(); ++i) {
        // 5.1 Let source ranges equal the ranges returned by the buffered attribute on the current SourceBuffer.
        TimeRanges* sourceRanges = ranges[i].get();

        // 5.2 If readyState is "ended", then set the end time on the last range in source ranges to highest end time.
        if (ended && sourceRanges->length())
            sourceRanges->add(sourceRanges->start(sourceRanges->length() - 1, ASSERT_NO_EXCEPTION), highestEndTime);

        // 5.3 Let new intersection ranges equal the the intersection between the intersection ranges and the source ranges.
        // 5.4 Replace the ranges in intersection ranges with the new intersection ranges.
        intersectionRanges->intersectWith(sourceRanges);
    }

    return intersectionRanges.release();
}

void MediaSourceBase::setDuration(double duration, ExceptionState& exceptionState)
{
    if (duration < 0.0 || std::isnan(duration)) {
        exceptionState.throwUninformativeAndGenericDOMException(InvalidAccessError);
        return;
    }
    if (!isOpen()) {
        exceptionState.throwUninformativeAndGenericDOMException(InvalidStateError);
        return;
    }

    // Synchronously process duration change algorithm to enforce any required
    // seek is started prior to returning.
    m_attachedElement->durationChanged(duration);
    m_webMediaSource->setDuration(duration);
}

void MediaSourceBase::setReadyState(const AtomicString& state)
{
    ASSERT(state == openKeyword() || state == closedKeyword() || state == endedKeyword());

    AtomicString oldState = readyState();
    WTF_LOG(Media, "MediaSourceBase::setReadyState() %p : %s -> %s", this, oldState.string().ascii().data(), state.string().ascii().data());

    if (state == closedKeyword()) {
        m_webMediaSource.clear();
        m_attachedElement = 0;
    }

    if (oldState == state)
        return;

    m_readyState = state;

    onReadyStateChange(oldState, state);
}

void MediaSourceBase::endOfStream(const AtomicString& error, ExceptionState& exceptionState)
{
    DEFINE_STATIC_LOCAL(const AtomicString, network, ("network", AtomicString::ConstructFromLiteral));
    DEFINE_STATIC_LOCAL(const AtomicString, decode, ("decode", AtomicString::ConstructFromLiteral));

    // 3.1 http://dvcs.w3.org/hg/html-media/raw-file/tip/media-source/media-source.html#dom-endofstream
    // 1. If the readyState attribute is not in the "open" state then throw an
    // InvalidStateError exception and abort these steps.
    if (!isOpen()) {
        exceptionState.throwUninformativeAndGenericDOMException(InvalidStateError);
        return;
    }

    WebMediaSource::EndOfStreamStatus eosStatus = WebMediaSource::EndOfStreamStatusNoError;

    if (error.isNull() || error.isEmpty()) {
        eosStatus = WebMediaSource::EndOfStreamStatusNoError;
    } else if (error == network) {
        eosStatus = WebMediaSource::EndOfStreamStatusNetworkError;
    } else if (error == decode) {
        eosStatus = WebMediaSource::EndOfStreamStatusDecodeError;
    } else {
        exceptionState.throwUninformativeAndGenericDOMException(InvalidAccessError);
        return;
    }

    // 2. Change the readyState attribute value to "ended".
    setReadyState(endedKeyword());
    m_webMediaSource->markEndOfStream(eosStatus);
}

bool MediaSourceBase::isOpen() const
{
    return readyState() == openKeyword();
}

bool MediaSourceBase::isClosed() const
{
    return readyState() == closedKeyword();
}

void MediaSourceBase::close()
{
    setReadyState(closedKeyword());
}

bool MediaSourceBase::attachToElement(HTMLMediaElement* element)
{
    if (m_attachedElement)
        return false;

    ASSERT(isClosed());

    TRACE_EVENT_ASYNC_BEGIN0("media", "MediaSourceBase::attachToElement", this);
    m_attachedElement = element;
    return true;
}

void MediaSourceBase::openIfInEndedState()
{
    if (m_readyState != endedKeyword())
        return;

    setReadyState(openKeyword());
    m_webMediaSource->unmarkEndOfStream();
}

bool MediaSourceBase::hasPendingActivity() const
{
    return m_attachedElement || m_webMediaSource
        || m_asyncEventQueue->hasPendingEvents()
        || ActiveDOMObject::hasPendingActivity();
}

void MediaSourceBase::stop()
{
    m_asyncEventQueue->close();
    if (!isClosed())
        setReadyState(closedKeyword());
    m_webMediaSource.clear();
}

PassOwnPtr<WebSourceBuffer> MediaSourceBase::createWebSourceBuffer(const String& type, const Vector<String>& codecs, ExceptionState& exceptionState)
{
    WebSourceBuffer* webSourceBuffer = 0;
    switch (m_webMediaSource->addSourceBuffer(type, codecs, &webSourceBuffer)) {
    case WebMediaSource::AddStatusOk:
        return adoptPtr(webSourceBuffer);
    case WebMediaSource::AddStatusNotSupported:
        ASSERT(!webSourceBuffer);
        // 2.2 https://dvcs.w3.org/hg/html-media/raw-file/default/media-source/media-source.html#widl-MediaSource-addSourceBuffer-SourceBuffer-DOMString-type
        // Step 2: If type contains a MIME type ... that is not supported with the types
        // specified for the other SourceBuffer objects in sourceBuffers, then throw
        // a NotSupportedError exception and abort these steps.
        exceptionState.throwUninformativeAndGenericDOMException(NotSupportedError);
        return nullptr;
    case WebMediaSource::AddStatusReachedIdLimit:
        ASSERT(!webSourceBuffer);
        // 2.2 https://dvcs.w3.org/hg/html-media/raw-file/default/media-source/media-source.html#widl-MediaSource-addSourceBuffer-SourceBuffer-DOMString-type
        // Step 3: If the user agent can't handle any more SourceBuffer objects then throw
        // a QuotaExceededError exception and abort these steps.
        exceptionState.throwUninformativeAndGenericDOMException(QuotaExceededError);
        return nullptr;
    }

    ASSERT_NOT_REACHED();
    return nullptr;
}

void MediaSourceBase::scheduleEvent(const AtomicString& eventName)
{
    ASSERT(m_asyncEventQueue);

    RefPtr<Event> event = Event::create(eventName);
    event->setTarget(this);

    m_asyncEventQueue->enqueueEvent(event.release());
}

ExecutionContext* MediaSourceBase::executionContext() const
{
    return ActiveDOMObject::executionContext();
}

URLRegistry& MediaSourceBase::registry() const
{
    return MediaSourceRegistry::registry();
}

}
<|endoftext|>


<commit_before><commit_msg>coverity#706468 Uncaught exception<commit_after><|endoftext|>


<commit_before>// Copyright (c) 2010 Satoshi Nakamoto
// Copyright (c) 2009-2019 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.

#include <consensus/validation.h>
#include <net.h>
#include <net_processing.h>
#include <node/context.h>
#include <validation.h>
#include <validationinterface.h>
#include <node/transaction.h>

#include <future>

TransactionError BroadcastTransaction(NodeContext& node, const CTransactionRef tx, std::string& err_string, const CAmount& max_tx_fee, bool relay, bool wait_callback)
{
    // BroadcastTransaction can be called by either sendrawtransaction RPC or wallet RPCs.
    // node.connman is assigned both before chain clients and before RPC server is accepting calls,
    // and reset after chain clients and RPC sever are stopped. node.connman should never be null here.
    assert(node.connman);
    assert(node.mempool);
    std::promise<void> promise;
    uint256 hashTx = tx->GetHash();
    bool callback_set = false;

    { // cs_main scope
    LOCK(cs_main);
    // If the transaction is already confirmed in the chain, don't do anything
    // and return early.
    CCoinsViewCache &view = ::ChainstateActive().CoinsTip();
    for (size_t o = 0; o < tx->vout.size(); o++) {
        const Coin& existingCoin = view.AccessCoin(COutPoint(hashTx, o));
        // IsSpent doesn't mean the coin is spent, it means the output doesn't exist.
        // So if the output does exist, then this transaction exists in the chain.
        if (!existingCoin.IsSpent()) return TransactionError::ALREADY_IN_CHAIN;
    }
    if (!node.mempool->exists(hashTx)) {
        // Transaction is not already in the mempool. Submit it.
        TxValidationState state;
        if (!AcceptToMemoryPool(*node.mempool, state, std::move(tx),
                nullptr /* plTxnReplaced */, false /* bypass_limits */, max_tx_fee)) {
            err_string = state.ToString();
            if (state.IsInvalid()) {
                if (state.GetResult() == TxValidationResult::TX_MISSING_INPUTS) {
                    return TransactionError::MISSING_INPUTS;
                }
                return TransactionError::MEMPOOL_REJECTED;
            } else {
                return TransactionError::MEMPOOL_ERROR;
            }
        }

        // Transaction was accepted to the mempool.

        if (wait_callback) {
            // For transactions broadcast from outside the wallet, make sure
            // that the wallet has been notified of the transaction before
            // continuing.
            //
            // This prevents a race where a user might call sendrawtransaction
            // with a transaction to/from their wallet, immediately call some
            // wallet RPC, and get a stale result because callbacks have not
            // yet been processed.
            CallFunctionInValidationInterfaceQueue([&promise] {
                promise.set_value();
            });
            callback_set = true;
        }
    }

    } // cs_main

    if (callback_set) {
        // Wait until Validation Interface clients have been notified of the
        // transaction entering the mempool.
        promise.get_future().wait();
    }

    if (relay) {
        // the mempool tracks locally submitted transactions to make a
        // best-effort of initial broadcast
        node.mempool->AddUnbroadcastTx(hashTx);

        LOCK(cs_main);
        RelayTransaction(hashTx, tx->GetWitnessHash(), *node.connman);
    }

    return TransactionError::OK;
}
<commit_msg>[BroadcastTransaction] Remove unsafe move operator<commit_after>// Copyright (c) 2010 Satoshi Nakamoto
// Copyright (c) 2009-2019 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.

#include <consensus/validation.h>
#include <net.h>
#include <net_processing.h>
#include <node/context.h>
#include <validation.h>
#include <validationinterface.h>
#include <node/transaction.h>

#include <future>

TransactionError BroadcastTransaction(NodeContext& node, const CTransactionRef tx, std::string& err_string, const CAmount& max_tx_fee, bool relay, bool wait_callback)
{
    // BroadcastTransaction can be called by either sendrawtransaction RPC or wallet RPCs.
    // node.connman is assigned both before chain clients and before RPC server is accepting calls,
    // and reset after chain clients and RPC sever are stopped. node.connman should never be null here.
    assert(node.connman);
    assert(node.mempool);
    std::promise<void> promise;
    uint256 hashTx = tx->GetHash();
    bool callback_set = false;

    { // cs_main scope
    LOCK(cs_main);
    // If the transaction is already confirmed in the chain, don't do anything
    // and return early.
    CCoinsViewCache &view = ::ChainstateActive().CoinsTip();
    for (size_t o = 0; o < tx->vout.size(); o++) {
        const Coin& existingCoin = view.AccessCoin(COutPoint(hashTx, o));
        // IsSpent doesn't mean the coin is spent, it means the output doesn't exist.
        // So if the output does exist, then this transaction exists in the chain.
        if (!existingCoin.IsSpent()) return TransactionError::ALREADY_IN_CHAIN;
    }
    if (!node.mempool->exists(hashTx)) {
        // Transaction is not already in the mempool. Submit it.
        TxValidationState state;
        if (!AcceptToMemoryPool(*node.mempool, state, tx,
                                nullptr /* plTxnReplaced */, false /* bypass_limits */, max_tx_fee)) {
            err_string = state.ToString();
            if (state.IsInvalid()) {
                if (state.GetResult() == TxValidationResult::TX_MISSING_INPUTS) {
                    return TransactionError::MISSING_INPUTS;
                }
                return TransactionError::MEMPOOL_REJECTED;
            } else {
                return TransactionError::MEMPOOL_ERROR;
            }
        }

        // Transaction was accepted to the mempool.

        if (wait_callback) {
            // For transactions broadcast from outside the wallet, make sure
            // that the wallet has been notified of the transaction before
            // continuing.
            //
            // This prevents a race where a user might call sendrawtransaction
            // with a transaction to/from their wallet, immediately call some
            // wallet RPC, and get a stale result because callbacks have not
            // yet been processed.
            CallFunctionInValidationInterfaceQueue([&promise] {
                promise.set_value();
            });
            callback_set = true;
        }
    }

    } // cs_main

    if (callback_set) {
        // Wait until Validation Interface clients have been notified of the
        // transaction entering the mempool.
        promise.get_future().wait();
    }

    if (relay) {
        // the mempool tracks locally submitted transactions to make a
        // best-effort of initial broadcast
        node.mempool->AddUnbroadcastTx(hashTx);

        LOCK(cs_main);
        RelayTransaction(hashTx, tx->GetWitnessHash(), *node.connman);
    }

    return TransactionError::OK;
}
<|endoftext|>


<commit_before>// This file is part of Eigen, a lightweight C++ template library
// for linear algebra.
//
// Copyright (C) 2008-2009 Gael Guennebaud <gael.guennebaud@inria.fr>
//
// Eigen is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; either
// version 3 of the License, or (at your option) any later version.
//
// Alternatively, you can redistribute it and/or
// modify it under the terms of the GNU General Public License as
// published by the Free Software Foundation; either version 2 of
// the License, or (at your option) any later version.
//
// Eigen 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 or the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License and a copy of the GNU General Public License along with
// Eigen. If not, see <http://www.gnu.org/licenses/>.

#include "main.h"

template<typename MatrixType> void array_for_matrix(const MatrixType& m)
{
  typedef typename MatrixType::Index Index;
  typedef typename MatrixType::Scalar Scalar;
  typedef typename NumTraits<Scalar>::Real RealScalar;
  typedef Matrix<Scalar, MatrixType::RowsAtCompileTime, 1> ColVectorType;
  typedef Matrix<Scalar, 1, MatrixType::ColsAtCompileTime> RowVectorType;

  Index rows = m.rows();
  Index cols = m.cols();

  MatrixType m1 = MatrixType::Random(rows, cols),
             m2 = MatrixType::Random(rows, cols),
             m3(rows, cols);

  ColVectorType cv1 = ColVectorType::Random(rows);
  RowVectorType rv1 = RowVectorType::Random(cols);

  Scalar  s1 = internal::random<Scalar>(),
          s2 = internal::random<Scalar>();

  // scalar addition
  VERIFY_IS_APPROX(m1.array() + s1, s1 + m1.array());
  VERIFY_IS_APPROX((m1.array() + s1).matrix(), MatrixType::Constant(rows,cols,s1) + m1);
  VERIFY_IS_APPROX(((m1*Scalar(2)).array() - s2).matrix(), (m1+m1) - MatrixType::Constant(rows,cols,s2) );
  m3 = m1;
  m3.array() += s2;
  VERIFY_IS_APPROX(m3, (m1.array() + s2).matrix());
  m3 = m1;
  m3.array() -= s1;
  VERIFY_IS_APPROX(m3, (m1.array() - s1).matrix());

  // reductions
  VERIFY_IS_APPROX(m1.colwise().sum().sum(), m1.sum());
  VERIFY_IS_APPROX(m1.rowwise().sum().sum(), m1.sum());
  if (!internal::isApprox(m1.sum(), (m1+m2).sum()))
    VERIFY_IS_NOT_APPROX(((m1+m2).rowwise().sum()).sum(), m1.sum());
  VERIFY_IS_APPROX(m1.colwise().sum(), m1.colwise().redux(internal::scalar_sum_op<Scalar>()));

  // vector-wise ops
  m3 = m1;
  VERIFY_IS_APPROX(m3.colwise() += cv1, m1.colwise() + cv1);
  m3 = m1;
  VERIFY_IS_APPROX(m3.colwise() -= cv1, m1.colwise() - cv1);
  m3 = m1;
  VERIFY_IS_APPROX(m3.rowwise() += rv1, m1.rowwise() + rv1);
  m3 = m1;
  VERIFY_IS_APPROX(m3.rowwise() -= rv1, m1.rowwise() - rv1);

  // empty objects
  VERIFY_IS_APPROX(m1.block(0,0,0,cols).colwise().sum(),  RowVectorType::Zero(cols));
  VERIFY_IS_APPROX(m1.block(0,0,rows,0).rowwise().prod(), ColVectorType::Ones(rows));

  // verify the const accessors exist
  const Scalar& ref_m1 = m.matrix().array().coeffRef(0);
  const Scalar& ref_m2 = m.matrix().array().coeffRef(0,0);
  const Scalar& ref_a1 = m.array().matrix().coeffRef(0);
  const Scalar& ref_a2 = m.array().matrix().coeffRef(0,0);
  VERIFY(&ref_a1 == &ref_m1);
  VERIFY(&ref_a2 == &ref_m2);
}

template<typename MatrixType> void comparisons(const MatrixType& m)
{
  typedef typename MatrixType::Index Index;
  typedef typename MatrixType::Scalar Scalar;
  typedef typename NumTraits<Scalar>::Real RealScalar;
  typedef Matrix<Scalar, MatrixType::RowsAtCompileTime, 1> VectorType;

  Index rows = m.rows();
  Index cols = m.cols();

  Index r = internal::random<Index>(0, rows-1),
        c = internal::random<Index>(0, cols-1);

  MatrixType m1 = MatrixType::Random(rows, cols),
             m2 = MatrixType::Random(rows, cols),
             m3(rows, cols);

  VERIFY(((m1.array() + Scalar(1)) > m1.array()).all());
  VERIFY(((m1.array() - Scalar(1)) < m1.array()).all());
  if (rows*cols>1)
  {
    m3 = m1;
    m3(r,c) += 1;
    VERIFY(! (m1.array() < m3.array()).all() );
    VERIFY(! (m1.array() > m3.array()).all() );
  }

  // comparisons to scalar
  VERIFY( (m1.array() != (m1(r,c)+1) ).any() );
  VERIFY( (m1.array() > (m1(r,c)-1) ).any() );
  VERIFY( (m1.array() < (m1(r,c)+1) ).any() );
  VERIFY( (m1.array() == m1(r,c) ).any() );

  // test Select
  VERIFY_IS_APPROX( (m1.array()<m2.array()).select(m1,m2), m1.cwiseMin(m2) );
  VERIFY_IS_APPROX( (m1.array()>m2.array()).select(m1,m2), m1.cwiseMax(m2) );
  Scalar mid = (m1.cwiseAbs().minCoeff() + m1.cwiseAbs().maxCoeff())/Scalar(2);
  for (int j=0; j<cols; ++j)
  for (int i=0; i<rows; ++i)
    m3(i,j) = internal::abs(m1(i,j))<mid ? 0 : m1(i,j);
  VERIFY_IS_APPROX( (m1.array().abs()<MatrixType::Constant(rows,cols,mid).array())
                        .select(MatrixType::Zero(rows,cols),m1), m3);
  // shorter versions:
  VERIFY_IS_APPROX( (m1.array().abs()<MatrixType::Constant(rows,cols,mid).array())
                        .select(0,m1), m3);
  VERIFY_IS_APPROX( (m1.array().abs()>=MatrixType::Constant(rows,cols,mid).array())
                        .select(m1,0), m3);
  // even shorter version:
  VERIFY_IS_APPROX( (m1.array().abs()<mid).select(0,m1), m3);

  // count
  VERIFY(((m1.array().abs()+1)>RealScalar(0.1)).count() == rows*cols);

  typedef Matrix<typename MatrixType::Index, Dynamic, 1> VectorOfIndices;

  // TODO allows colwise/rowwise for array
  VERIFY_IS_APPROX(((m1.array().abs()+1)>RealScalar(0.1)).matrix().colwise().count(), VectorOfIndices::Constant(cols,rows).transpose());
  VERIFY_IS_APPROX(((m1.array().abs()+1)>RealScalar(0.1)).matrix().rowwise().count(), VectorOfIndices::Constant(rows, cols));
}

template<typename VectorType> void lpNorm(const VectorType& v)
{
  VectorType u = VectorType::Random(v.size());

  VERIFY_IS_APPROX(u.template lpNorm<Infinity>(), u.cwiseAbs().maxCoeff());
  VERIFY_IS_APPROX(u.template lpNorm<1>(), u.cwiseAbs().sum());
  VERIFY_IS_APPROX(u.template lpNorm<2>(), internal::sqrt(u.array().abs().square().sum()));
  VERIFY_IS_APPROX(internal::pow(u.template lpNorm<5>(), typename VectorType::RealScalar(5)), u.array().abs().pow(5).sum());
}

void test_array_for_matrix()
{
  for(int i = 0; i < g_repeat; i++) {
    CALL_SUBTEST_1( array_for_matrix(Matrix<float, 1, 1>()) );
    CALL_SUBTEST_2( array_for_matrix(Matrix2f()) );
    CALL_SUBTEST_3( array_for_matrix(Matrix4d()) );
    CALL_SUBTEST_4( array_for_matrix(MatrixXcf(3, 3)) );
    CALL_SUBTEST_5( array_for_matrix(MatrixXf(8, 12)) );
    CALL_SUBTEST_6( array_for_matrix(MatrixXi(8, 12)) );
  }
  for(int i = 0; i < g_repeat; i++) {
    CALL_SUBTEST_1( comparisons(Matrix<float, 1, 1>()) );
    CALL_SUBTEST_2( comparisons(Matrix2f()) );
    CALL_SUBTEST_3( comparisons(Matrix4d()) );
    CALL_SUBTEST_5( comparisons(MatrixXf(8, 12)) );
    CALL_SUBTEST_6( comparisons(MatrixXi(8, 12)) );
  }
  for(int i = 0; i < g_repeat; i++) {
    CALL_SUBTEST_1( lpNorm(Matrix<float, 1, 1>()) );
    CALL_SUBTEST_2( lpNorm(Vector2f()) );
    CALL_SUBTEST_7( lpNorm(Vector3d()) );
    CALL_SUBTEST_8( lpNorm(Vector4f()) );
    CALL_SUBTEST_5( lpNorm(VectorXf(16)) );
    CALL_SUBTEST_4( lpNorm(VectorXcf(10)) );
  }
}
<commit_msg>fix array_for_matrix unit test<commit_after>// This file is part of Eigen, a lightweight C++ template library
// for linear algebra.
//
// Copyright (C) 2008-2009 Gael Guennebaud <gael.guennebaud@inria.fr>
//
// Eigen is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; either
// version 3 of the License, or (at your option) any later version.
//
// Alternatively, you can redistribute it and/or
// modify it under the terms of the GNU General Public License as
// published by the Free Software Foundation; either version 2 of
// the License, or (at your option) any later version.
//
// Eigen 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 or the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License and a copy of the GNU General Public License along with
// Eigen. If not, see <http://www.gnu.org/licenses/>.

#include "main.h"

template<typename MatrixType> void array_for_matrix(const MatrixType& m)
{
  typedef typename MatrixType::Index Index;
  typedef typename MatrixType::Scalar Scalar;
  typedef typename NumTraits<Scalar>::Real RealScalar;
  typedef Matrix<Scalar, MatrixType::RowsAtCompileTime, 1> ColVectorType;
  typedef Matrix<Scalar, 1, MatrixType::ColsAtCompileTime> RowVectorType;

  Index rows = m.rows();
  Index cols = m.cols();

  MatrixType m1 = MatrixType::Random(rows, cols),
             m2 = MatrixType::Random(rows, cols),
             m3(rows, cols);

  ColVectorType cv1 = ColVectorType::Random(rows);
  RowVectorType rv1 = RowVectorType::Random(cols);

  Scalar  s1 = internal::random<Scalar>(),
          s2 = internal::random<Scalar>();

  // scalar addition
  VERIFY_IS_APPROX(m1.array() + s1, s1 + m1.array());
  VERIFY_IS_APPROX((m1.array() + s1).matrix(), MatrixType::Constant(rows,cols,s1) + m1);
  VERIFY_IS_APPROX(((m1*Scalar(2)).array() - s2).matrix(), (m1+m1) - MatrixType::Constant(rows,cols,s2) );
  m3 = m1;
  m3.array() += s2;
  VERIFY_IS_APPROX(m3, (m1.array() + s2).matrix());
  m3 = m1;
  m3.array() -= s1;
  VERIFY_IS_APPROX(m3, (m1.array() - s1).matrix());

  // reductions
  VERIFY_IS_MUCH_SMALLER_THAN(m1.colwise().sum().sum() - m1.sum(), m1.cwiseAbs().maxCoeff());
  VERIFY_IS_MUCH_SMALLER_THAN(m1.rowwise().sum().sum() - m1.sum(), m1.cwiseAbs().maxCoeff());
  VERIFY_IS_MUCH_SMALLER_THAN(m1.colwise().sum() + m2.colwise().sum() - (m1+m2).colwise().sum(), (m1+m2).cwiseAbs().maxCoeff());
  VERIFY_IS_MUCH_SMALLER_THAN(m1.rowwise().sum() - m2.rowwise().sum() - (m1-m2).rowwise().sum(), (m1-m2).cwiseAbs().maxCoeff());
  VERIFY_IS_APPROX(m1.colwise().sum(), m1.colwise().redux(internal::scalar_sum_op<Scalar>()));

  // vector-wise ops
  m3 = m1;
  VERIFY_IS_APPROX(m3.colwise() += cv1, m1.colwise() + cv1);
  m3 = m1;
  VERIFY_IS_APPROX(m3.colwise() -= cv1, m1.colwise() - cv1);
  m3 = m1;
  VERIFY_IS_APPROX(m3.rowwise() += rv1, m1.rowwise() + rv1);
  m3 = m1;
  VERIFY_IS_APPROX(m3.rowwise() -= rv1, m1.rowwise() - rv1);

  // empty objects
  VERIFY_IS_APPROX(m1.block(0,0,0,cols).colwise().sum(),  RowVectorType::Zero(cols));
  VERIFY_IS_APPROX(m1.block(0,0,rows,0).rowwise().prod(), ColVectorType::Ones(rows));

  // verify the const accessors exist
  const Scalar& ref_m1 = m.matrix().array().coeffRef(0);
  const Scalar& ref_m2 = m.matrix().array().coeffRef(0,0);
  const Scalar& ref_a1 = m.array().matrix().coeffRef(0);
  const Scalar& ref_a2 = m.array().matrix().coeffRef(0,0);
  VERIFY(&ref_a1 == &ref_m1);
  VERIFY(&ref_a2 == &ref_m2);
}

template<typename MatrixType> void comparisons(const MatrixType& m)
{
  typedef typename MatrixType::Index Index;
  typedef typename MatrixType::Scalar Scalar;
  typedef typename NumTraits<Scalar>::Real RealScalar;
  typedef Matrix<Scalar, MatrixType::RowsAtCompileTime, 1> VectorType;

  Index rows = m.rows();
  Index cols = m.cols();

  Index r = internal::random<Index>(0, rows-1),
        c = internal::random<Index>(0, cols-1);

  MatrixType m1 = MatrixType::Random(rows, cols),
             m2 = MatrixType::Random(rows, cols),
             m3(rows, cols);

  VERIFY(((m1.array() + Scalar(1)) > m1.array()).all());
  VERIFY(((m1.array() - Scalar(1)) < m1.array()).all());
  if (rows*cols>1)
  {
    m3 = m1;
    m3(r,c) += 1;
    VERIFY(! (m1.array() < m3.array()).all() );
    VERIFY(! (m1.array() > m3.array()).all() );
  }

  // comparisons to scalar
  VERIFY( (m1.array() != (m1(r,c)+1) ).any() );
  VERIFY( (m1.array() > (m1(r,c)-1) ).any() );
  VERIFY( (m1.array() < (m1(r,c)+1) ).any() );
  VERIFY( (m1.array() == m1(r,c) ).any() );

  // test Select
  VERIFY_IS_APPROX( (m1.array()<m2.array()).select(m1,m2), m1.cwiseMin(m2) );
  VERIFY_IS_APPROX( (m1.array()>m2.array()).select(m1,m2), m1.cwiseMax(m2) );
  Scalar mid = (m1.cwiseAbs().minCoeff() + m1.cwiseAbs().maxCoeff())/Scalar(2);
  for (int j=0; j<cols; ++j)
  for (int i=0; i<rows; ++i)
    m3(i,j) = internal::abs(m1(i,j))<mid ? 0 : m1(i,j);
  VERIFY_IS_APPROX( (m1.array().abs()<MatrixType::Constant(rows,cols,mid).array())
                        .select(MatrixType::Zero(rows,cols),m1), m3);
  // shorter versions:
  VERIFY_IS_APPROX( (m1.array().abs()<MatrixType::Constant(rows,cols,mid).array())
                        .select(0,m1), m3);
  VERIFY_IS_APPROX( (m1.array().abs()>=MatrixType::Constant(rows,cols,mid).array())
                        .select(m1,0), m3);
  // even shorter version:
  VERIFY_IS_APPROX( (m1.array().abs()<mid).select(0,m1), m3);

  // count
  VERIFY(((m1.array().abs()+1)>RealScalar(0.1)).count() == rows*cols);

  typedef Matrix<typename MatrixType::Index, Dynamic, 1> VectorOfIndices;

  // TODO allows colwise/rowwise for array
  VERIFY_IS_APPROX(((m1.array().abs()+1)>RealScalar(0.1)).matrix().colwise().count(), VectorOfIndices::Constant(cols,rows).transpose());
  VERIFY_IS_APPROX(((m1.array().abs()+1)>RealScalar(0.1)).matrix().rowwise().count(), VectorOfIndices::Constant(rows, cols));
}

template<typename VectorType> void lpNorm(const VectorType& v)
{
  VectorType u = VectorType::Random(v.size());

  VERIFY_IS_APPROX(u.template lpNorm<Infinity>(), u.cwiseAbs().maxCoeff());
  VERIFY_IS_APPROX(u.template lpNorm<1>(), u.cwiseAbs().sum());
  VERIFY_IS_APPROX(u.template lpNorm<2>(), internal::sqrt(u.array().abs().square().sum()));
  VERIFY_IS_APPROX(internal::pow(u.template lpNorm<5>(), typename VectorType::RealScalar(5)), u.array().abs().pow(5).sum());
}

void test_array_for_matrix()
{
  int maxsize = 40;
  for(int i = 0; i < g_repeat; i++) {
    CALL_SUBTEST_1( array_for_matrix(Matrix<float, 1, 1>()) );
    CALL_SUBTEST_2( array_for_matrix(Matrix2f()) );
    CALL_SUBTEST_3( array_for_matrix(Matrix4d()) );
    CALL_SUBTEST_4( array_for_matrix(MatrixXcf(internal::random<int>(1,maxsize), internal::random<int>(1,maxsize))) );
    CALL_SUBTEST_5( array_for_matrix(MatrixXf(internal::random<int>(1,maxsize), internal::random<int>(1,maxsize))) );
    CALL_SUBTEST_6( array_for_matrix(MatrixXi(internal::random<int>(1,maxsize), internal::random<int>(1,maxsize))) );
  }
  for(int i = 0; i < g_repeat; i++) {
    CALL_SUBTEST_1( comparisons(Matrix<float, 1, 1>()) );
    CALL_SUBTEST_2( comparisons(Matrix2f()) );
    CALL_SUBTEST_3( comparisons(Matrix4d()) );
    CALL_SUBTEST_5( comparisons(MatrixXf(internal::random<int>(1,maxsize), internal::random<int>(1,maxsize))) );
    CALL_SUBTEST_6( comparisons(MatrixXi(internal::random<int>(1,maxsize), internal::random<int>(1,maxsize))) );
  }
  for(int i = 0; i < g_repeat; i++) {
    CALL_SUBTEST_1( lpNorm(Matrix<float, 1, 1>()) );
    CALL_SUBTEST_2( lpNorm(Vector2f()) );
    CALL_SUBTEST_7( lpNorm(Vector3d()) );
    CALL_SUBTEST_8( lpNorm(Vector4f()) );
    CALL_SUBTEST_5( lpNorm(VectorXf(internal::random<int>(1,maxsize))) );
    CALL_SUBTEST_4( lpNorm(VectorXcf(internal::random<int>(1,maxsize))) );
  }
}
<|endoftext|>


<commit_before>/**
 * @file
 * @brief Definition of object with digitized pixel hit
 * @copyright Copyright (c) 2017 CERN and the Allpix Squared authors.
 * This software is distributed under the terms of the MIT License, copied verbatim in the file "LICENSE.md".
 * In applying this license, CERN does not waive the privileges and immunities granted to it by virtue of its status as an
 * Intergovernmental Organization or submit itself to any jurisdiction.
 */

#ifndef ALLPIX_PIXEL_HIT_H
#define ALLPIX_PIXEL_HIT_H

#include <Math/DisplacementVector2D.h>

#include <TRef.h>

#include "MCParticle.hpp"
#include "Object.hpp"
#include "PixelCharge.hpp"

#include "Pixel.hpp"

namespace allpix {
    /**
     * @ingroup Objects
     * @brief Pixel triggered in an event after digitization
     */
    class PixelHit : public Object {
    public:
        /**
         * @brief Construct a digitized pixel hit
         * @param pixel Object holding the information of the pixel
         * @param time Timing of the occurence of the hit
         * @param signal Signal data produced by the digitizer
         * @param pixel_charge Optional pointer to the related pixel charge
         */
        PixelHit(Pixel pixel, double time, double signal, const PixelCharge* pixel_charge = nullptr);

        /**
         * @brief Get the pixel hit
         * @return Pixel indices in the grid
         */
        const Pixel& getPixel() const;
        /**
         * @brief Shortcut to retrieve the pixel indices
         * @return Index of the pixel
         */
        Pixel::Index getIndex() const;
        /**
         * @brief Get the timing data of the hit
         * @return Timestamp
         */
        double getTime() const { return time_; }
        /**
         * @brief Get the signal data for the hit
         * @return Digitized signal
         */
        double getSignal() const { return signal_; }

        /**
         * @brief Get related pixel charge
         * @return Possible related pixel charge
         */
        const PixelCharge* getPixelCharge() const;
        /**
         * @brief Get the Monte-Carlo particles resulting in this pixel hit
         * @return List of all related Monte-Carlo particles
         */
        std::vector<const MCParticle*> getMCParticles() const;

        /**
         * @brief Print an ASCII representation of PixelHit to the given stream
         * @param out Stream to print to
         */
        void print(std::ostream& out) const;

        /**
         * @brief ROOT class definition
         */
        ClassDef(PixelHit, 4);
        /**
         * @brief Default constructor for ROOT I/O
         */
        PixelHit() = default;

    private:
        Pixel pixel_;
        double time_{};
        double signal_{};

        TRef pixel_charge_;
        TRefArray mc_particles_;
    };

    /**
     * @brief Typedef for message carrying pixel hits
     */
    using PixelHitMessage = Message<PixelHit>;
} // namespace allpix

#endif
<commit_msg>PixelHit: explicitly override base class function<commit_after>/**
 * @file
 * @brief Definition of object with digitized pixel hit
 * @copyright Copyright (c) 2017 CERN and the Allpix Squared authors.
 * This software is distributed under the terms of the MIT License, copied verbatim in the file "LICENSE.md".
 * In applying this license, CERN does not waive the privileges and immunities granted to it by virtue of its status as an
 * Intergovernmental Organization or submit itself to any jurisdiction.
 */

#ifndef ALLPIX_PIXEL_HIT_H
#define ALLPIX_PIXEL_HIT_H

#include <Math/DisplacementVector2D.h>

#include <TRef.h>

#include "MCParticle.hpp"
#include "Object.hpp"
#include "PixelCharge.hpp"

#include "Pixel.hpp"

namespace allpix {
    /**
     * @ingroup Objects
     * @brief Pixel triggered in an event after digitization
     */
    class PixelHit : public Object {
    public:
        /**
         * @brief Construct a digitized pixel hit
         * @param pixel Object holding the information of the pixel
         * @param time Timing of the occurence of the hit
         * @param signal Signal data produced by the digitizer
         * @param pixel_charge Optional pointer to the related pixel charge
         */
        PixelHit(Pixel pixel, double time, double signal, const PixelCharge* pixel_charge = nullptr);

        /**
         * @brief Get the pixel hit
         * @return Pixel indices in the grid
         */
        const Pixel& getPixel() const;
        /**
         * @brief Shortcut to retrieve the pixel indices
         * @return Index of the pixel
         */
        Pixel::Index getIndex() const;
        /**
         * @brief Get the timing data of the hit
         * @return Timestamp
         */
        double getTime() const { return time_; }
        /**
         * @brief Get the signal data for the hit
         * @return Digitized signal
         */
        double getSignal() const { return signal_; }

        /**
         * @brief Get related pixel charge
         * @return Possible related pixel charge
         */
        const PixelCharge* getPixelCharge() const;
        /**
         * @brief Get the Monte-Carlo particles resulting in this pixel hit
         * @return List of all related Monte-Carlo particles
         */
        std::vector<const MCParticle*> getMCParticles() const;

        /**
         * @brief Print an ASCII representation of PixelHit to the given stream
         * @param out Stream to print to
         */
        void print(std::ostream& out) const override;

        /**
         * @brief ROOT class definition
         */
        ClassDef(PixelHit, 4);
        /**
         * @brief Default constructor for ROOT I/O
         */
        PixelHit() = default;

    private:
        Pixel pixel_;
        double time_{};
        double signal_{};

        TRef pixel_charge_;
        TRefArray mc_particles_;
    };

    /**
     * @brief Typedef for message carrying pixel hits
     */
    using PixelHitMessage = Message<PixelHit>;
} // namespace allpix

#endif
<|endoftext|>


<commit_before>#include "selfdrive/ui/qt/sidebar.h"

#include <QMouseEvent>

#include "selfdrive/ui/qt/qt_window.h"
#include "selfdrive/common/util.h"
#include "selfdrive/hardware/hw.h"
#include "selfdrive/ui/qt/util.h"

void Sidebar::drawMetric(QPainter &p, const QString &label, const QString &val, QColor c, int y) {
  const QRect rect = {30, y, 240, val.isEmpty() ? (label.contains("\n") ? 124 : 100) : 148};

  p.setPen(Qt::NoPen);
  p.setBrush(QBrush(c));
  p.setClipRect(rect.x() + 6, rect.y(), 18, rect.height(), Qt::ClipOperation::ReplaceClip);
  p.drawRoundedRect(QRect(rect.x() + 6, rect.y() + 6, 100, rect.height() - 12), 10, 10);
  p.setClipping(false);

  QPen pen = QPen(QColor(0xff, 0xff, 0xff, 0x55));
  pen.setWidth(2);
  p.setPen(pen);
  p.setBrush(Qt::NoBrush);
  p.drawRoundedRect(rect, 20, 20);

  p.setPen(QColor(0xff, 0xff, 0xff));
  if (val.isEmpty()) {
    configFont(p, "Open Sans", 35, "Bold");
    const QRect r = QRect(rect.x() + 30, rect.y(), rect.width() - 40, rect.height());
    p.drawText(r, Qt::AlignCenter, label);
  } else {
    configFont(p, "Open Sans", 58, "Bold");
    p.drawText(rect.x() + 50, rect.y() + 71, val);
    configFont(p, "Open Sans", 35, "Regular");
    p.drawText(rect.x() + 50, rect.y() + 50 + 77, label);
  }
}

Sidebar::Sidebar(QWidget *parent) : QFrame(parent) {
  home_img = QImage("../assets/images/button_home.png").scaled(180, 180, Qt::KeepAspectRatio, Qt::SmoothTransformation);
  settings_img = QImage("../assets/images/button_settings.png").scaled(settings_btn.width(), settings_btn.height(), Qt::IgnoreAspectRatio, Qt::SmoothTransformation);

  connect(this, &Sidebar::valueChanged, [=] { update(); });

  setFixedWidth(300);
  setMinimumHeight(vwp_h);
  setStyleSheet("background-color: rgb(57, 57, 57);");
}

void Sidebar::mousePressEvent(QMouseEvent *event) {
  if (settings_btn.contains(event->pos())) {
    emit openSettings();
  }
}

void Sidebar::updateState(const UIState &s) {
  auto &sm = *(s.sm);

  auto deviceState = sm["deviceState"].getDeviceState();
  setProperty("netType", network_type[deviceState.getNetworkType()]);
  int strength = (int)deviceState.getNetworkStrength();
  setProperty("netStrength", strength > 0 ? strength + 1 : 0);

  auto last_ping = deviceState.getLastAthenaPingTime();
  if (last_ping == 0) {
    setProperty("connectStr", "OFFLINE");
    setProperty("connectStatus", warning_color);
  } else {
    bool online = nanos_since_boot() - last_ping < 80e9;
    setProperty("connectStr",  online ? "ONLINE" : "ERROR");
    setProperty("connectStatus", online ? good_color : danger_color);
  }

  QColor tempStatus = danger_color;
  auto ts = deviceState.getThermalStatus();
  if (ts == cereal::DeviceState::ThermalStatus::GREEN) {
    tempStatus = good_color;
  } else if (ts == cereal::DeviceState::ThermalStatus::YELLOW) {
    tempStatus = warning_color;
  }
  setProperty("tempStatus", tempStatus);
  setProperty("tempVal", (int)deviceState.getAmbientTempC());

  QString pandaStr = "VEHICLE\nONLINE";
  QColor pandaStatus = good_color;
  if (s.scene.pandaType == cereal::PandaState::PandaType::UNKNOWN) {
    pandaStatus = danger_color;
    pandaStr = "NO\nPANDA";
  } else if (!sm["liveLocationKalman"].getLiveLocationKalman().getGpsOK()) {
    pandaStatus = warning_color;
    pandaStr = "GPS\nSEARCHING";
  }
  setProperty("pandaStr", pandaStr);
  setProperty("pandaStatus", pandaStatus);
}

void Sidebar::paintEvent(QPaintEvent *event) {
  QPainter p(this);
  p.setPen(Qt::NoPen);
  p.setRenderHint(QPainter::Antialiasing);

  // static imgs
  p.setOpacity(0.65);
  p.drawImage(settings_btn.x(), settings_btn.y(), settings_img);
  p.setOpacity(1.0);
  p.drawImage(60, 1080 - 180 - 40, home_img);

  // network
  int x = 58;
  const QColor gray(0x54, 0x54, 0x54);
  for (int i = 0; i < 5; ++i) {
    p.setBrush(i < net_strength ? Qt::white : gray);
    p.drawEllipse(x, 196, 27, 27);
    x += 37;
  }

  configFont(p, "Open Sans", 35, "Regular");
  p.setPen(QColor(0xff, 0xff, 0xff));
  const QRect r = QRect(50, 247, 100, 50);
  p.drawText(r, Qt::AlignCenter, net_type);

  // metrics
  drawMetric(p, "TEMP", QString("%1°C").arg(temp_val), temp_status, 338);
  drawMetric(p, panda_str, "", panda_status, 518);
  drawMetric(p, "CONNECT\n" + connect_str, "", connect_status, 676);
}
<commit_msg>sidebar: only show gps indicator while onroad<commit_after>#include "selfdrive/ui/qt/sidebar.h"

#include <QMouseEvent>

#include "selfdrive/ui/qt/qt_window.h"
#include "selfdrive/common/util.h"
#include "selfdrive/hardware/hw.h"
#include "selfdrive/ui/qt/util.h"

void Sidebar::drawMetric(QPainter &p, const QString &label, const QString &val, QColor c, int y) {
  const QRect rect = {30, y, 240, val.isEmpty() ? (label.contains("\n") ? 124 : 100) : 148};

  p.setPen(Qt::NoPen);
  p.setBrush(QBrush(c));
  p.setClipRect(rect.x() + 6, rect.y(), 18, rect.height(), Qt::ClipOperation::ReplaceClip);
  p.drawRoundedRect(QRect(rect.x() + 6, rect.y() + 6, 100, rect.height() - 12), 10, 10);
  p.setClipping(false);

  QPen pen = QPen(QColor(0xff, 0xff, 0xff, 0x55));
  pen.setWidth(2);
  p.setPen(pen);
  p.setBrush(Qt::NoBrush);
  p.drawRoundedRect(rect, 20, 20);

  p.setPen(QColor(0xff, 0xff, 0xff));
  if (val.isEmpty()) {
    configFont(p, "Open Sans", 35, "Bold");
    const QRect r = QRect(rect.x() + 30, rect.y(), rect.width() - 40, rect.height());
    p.drawText(r, Qt::AlignCenter, label);
  } else {
    configFont(p, "Open Sans", 58, "Bold");
    p.drawText(rect.x() + 50, rect.y() + 71, val);
    configFont(p, "Open Sans", 35, "Regular");
    p.drawText(rect.x() + 50, rect.y() + 50 + 77, label);
  }
}

Sidebar::Sidebar(QWidget *parent) : QFrame(parent) {
  home_img = QImage("../assets/images/button_home.png").scaled(180, 180, Qt::KeepAspectRatio, Qt::SmoothTransformation);
  settings_img = QImage("../assets/images/button_settings.png").scaled(settings_btn.width(), settings_btn.height(), Qt::IgnoreAspectRatio, Qt::SmoothTransformation);

  connect(this, &Sidebar::valueChanged, [=] { update(); });

  setFixedWidth(300);
  setMinimumHeight(vwp_h);
  setStyleSheet("background-color: rgb(57, 57, 57);");
}

void Sidebar::mousePressEvent(QMouseEvent *event) {
  if (settings_btn.contains(event->pos())) {
    emit openSettings();
  }
}

void Sidebar::updateState(const UIState &s) {
  auto &sm = *(s.sm);

  auto deviceState = sm["deviceState"].getDeviceState();
  setProperty("netType", network_type[deviceState.getNetworkType()]);
  int strength = (int)deviceState.getNetworkStrength();
  setProperty("netStrength", strength > 0 ? strength + 1 : 0);

  auto last_ping = deviceState.getLastAthenaPingTime();
  if (last_ping == 0) {
    setProperty("connectStr", "OFFLINE");
    setProperty("connectStatus", warning_color);
  } else {
    bool online = nanos_since_boot() - last_ping < 80e9;
    setProperty("connectStr",  online ? "ONLINE" : "ERROR");
    setProperty("connectStatus", online ? good_color : danger_color);
  }

  QColor tempStatus = danger_color;
  auto ts = deviceState.getThermalStatus();
  if (ts == cereal::DeviceState::ThermalStatus::GREEN) {
    tempStatus = good_color;
  } else if (ts == cereal::DeviceState::ThermalStatus::YELLOW) {
    tempStatus = warning_color;
  }
  setProperty("tempStatus", tempStatus);
  setProperty("tempVal", (int)deviceState.getAmbientTempC());

  QString pandaStr = "VEHICLE\nONLINE";
  QColor pandaStatus = good_color;
  if (s.scene.pandaType == cereal::PandaState::PandaType::UNKNOWN) {
    pandaStatus = danger_color;
    pandaStr = "NO\nPANDA";
  } else if (s.scene.started && !sm["liveLocationKalman"].getLiveLocationKalman().getGpsOK()) {
    pandaStatus = warning_color;
    pandaStr = "GPS\nSEARCHING";
  }
  setProperty("pandaStr", pandaStr);
  setProperty("pandaStatus", pandaStatus);
}

void Sidebar::paintEvent(QPaintEvent *event) {
  QPainter p(this);
  p.setPen(Qt::NoPen);
  p.setRenderHint(QPainter::Antialiasing);

  // static imgs
  p.setOpacity(0.65);
  p.drawImage(settings_btn.x(), settings_btn.y(), settings_img);
  p.setOpacity(1.0);
  p.drawImage(60, 1080 - 180 - 40, home_img);

  // network
  int x = 58;
  const QColor gray(0x54, 0x54, 0x54);
  for (int i = 0; i < 5; ++i) {
    p.setBrush(i < net_strength ? Qt::white : gray);
    p.drawEllipse(x, 196, 27, 27);
    x += 37;
  }

  configFont(p, "Open Sans", 35, "Regular");
  p.setPen(QColor(0xff, 0xff, 0xff));
  const QRect r = QRect(50, 247, 100, 50);
  p.drawText(r, Qt::AlignCenter, net_type);

  // metrics
  drawMetric(p, "TEMP", QString("%1°C").arg(temp_val), temp_status, 338);
  drawMetric(p, panda_str, "", panda_status, 518);
  drawMetric(p, "CONNECT\n" + connect_str, "", connect_status, 676);
}
<|endoftext|>


<commit_before>//**************************************************************************************************
//
//     OSSIM Open Source Geospatial Data Processing Library
//     See top level LICENSE.txt file for license information
//
//**************************************************************************************************

#include "ossimDescriptorSource.h"
#include "../AtpOpenCV.h"
#include <ossim/imaging/ossimImageData.h>
#include <ossim/base/ossimKeywordlist.h>
#include <ossim/base/ossimConstants.h>
#include <ossim/imaging/ossimImageDataFactory.h>
#include <ossim/projection/ossimSensorModel.h>

#include <opencv2/opencv.hpp>
#include <opencv2/features2d/features2d.hpp>
#include <opencv2/highgui/highgui.hpp>
#include <opencv2/xfeatures2d.hpp>

namespace ATP
{
static const int DEFAULT_CMP_PATCH_SIZING_FACTOR = 2;
static const double DEFAULT_NOMINAL_POSITION_ERROR = 50; // meters

ossimDescriptorSource::ossimDescriptorSource()
{
}

ossimDescriptorSource::ossimDescriptorSource(ossimConnectableObject::ConnectableObjectList& inputSources)
: AtpTileSource(inputSources)
{
   initialize();
}

ossimDescriptorSource::ossimDescriptorSource(AtpGeneratorBase* generator)
: AtpTileSource(generator)
{
}

ossimDescriptorSource::~ossimDescriptorSource()
{
}

void ossimDescriptorSource::initialize()
{
   // Base class initializes ref and cmp chain datat members and associated IVTs. Subsequent call
   // to base class setViewGeom() will initialize the associated IVTs:
   AtpTileSource::initialize();
}

ossimRefPtr<ossimImageData> ossimDescriptorSource::getTile(const ossimIrect& tileRect,
                                                            ossim_uint32 resLevel)
{
   static const char* MODULE = "ossimDescriptorSource::getTile()  ";
   AtpConfig& config = AtpConfig::instance();

   if (config.diagnosticLevel(2))
      clog<<"\n\n"<< MODULE << " -- tileRect: "<<tileRect<<endl;
   m_tiePoints.clear();

   if(!m_tile.get())
   {
      // try to initialize
      initialize();
      if(!m_tile.get()){
         clog << MODULE << " ERROR: could not initialize tile\n";
         return m_tile;
      }
   }

   // Make sure there are at least two images as input.
   if(getNumberOfInputs() < 2)
   {
      clog << MODULE << " ERROR: wrong number of inputs " << getNumberOfInputs() << " when expecting at least 2 \n";
      return 0;
   }

   // The tileRect passed in is in a common map-projected view space. Need to transform the rect
   // into image space for both ref and cmp images:
   ossimIrect refRect (m_refIVT->getViewToImageBounds(tileRect));
   ossimIrect cmpRect (m_cmpIVT->getViewToImageBounds(tileRect));

   // Retrieve both the ref and cmp image data
   ossimRefPtr<ossimImageData> ref_tile = m_refChain->getTile(refRect, resLevel);
   if (ref_tile->getDataObjectStatus() == OSSIM_EMPTY)
   {
      clog << MODULE << " ERROR: could not get REF tile with rect " << refRect << "\n";
      return m_tile;
   }
   if (config.diagnosticLevel(5))
      ref_tile->write("REF_TILE.RAS");

   ossimRefPtr<ossimImageData> cmp_tile = m_cmpChain->getTile(cmpRect, resLevel);
   if (cmp_tile->getDataObjectStatus() == OSSIM_EMPTY)
   {
      clog << MODULE << " ERROR: could not get CMP tile with rect " << cmpRect << "\n";
      return m_tile;
   }
   if (config.diagnosticLevel(5))
      cmp_tile->write("CMP_TILE.RAS");

   m_tile = ref_tile;

   // Convert both into OpenCV Mat objects using the Ipl image.
   IplImage* refImage = convertToIpl32(ref_tile.get());
   IplImage* cmpImage = convertToIpl32(cmp_tile.get());
   cv::Mat queryImg = cv::cvarrToMat(refImage);
   cv::Mat trainImg = cv::cvarrToMat(cmpImage);

   // Get the KeyPoints using appropriate descriptor.
   std::vector<cv::KeyPoint> kpA;
   std::vector<cv::KeyPoint> kpB;
   cv::Mat desA;
   cv::Mat desB;

   std::string descriptorType = config.getParameter("descriptor").asString();
   transform(descriptorType.begin(), descriptorType.end(), descriptorType.begin(),::toupper);
   if(descriptorType == "AKAZE")
   {
      cv::Ptr<cv::AKAZE> detector = cv::AKAZE::create();
      detector->detectAndCompute(queryImg, cv::noArray(), kpA, desA);
      detector->detectAndCompute(trainImg, cv::noArray(), kpB, desB);
   }
   else if(descriptorType == "KAZE")
   {
      cv::Ptr<cv::KAZE> detector = cv::KAZE::create();
      detector->detectAndCompute(queryImg, cv::noArray(), kpA, desA);
      detector->detectAndCompute(trainImg, cv::noArray(), kpB, desB);
   }
   else if(descriptorType == "ORB")
   {
      // For some reason orb wants multiple channel mats so fake it.
      if (queryImg.channels() == 1)
      {
         std::vector<cv::Mat> channels;
         channels.push_back(queryImg);
         channels.push_back(queryImg);
         channels.push_back(queryImg);
         cv::merge(channels, queryImg);
      }

      if (trainImg.channels() == 1)
      {
         std::vector<cv::Mat> channels;
         channels.push_back(trainImg);
         channels.push_back(trainImg);
         channels.push_back(trainImg);
         cv::merge(channels, trainImg);
      }

      cv::Ptr<cv::ORB> detector = cv::ORB::create();
      detector->detectAndCompute(queryImg, cv::noArray(), kpA, desA);
      detector->detectAndCompute(trainImg, cv::noArray(), kpB, desB);
   }
   else if(descriptorType == "SURF")
   {
      queryImg.convertTo(queryImg, CV_8U);
      trainImg.convertTo(trainImg, CV_8U);

      cv::Ptr<cv::xfeatures2d::SURF> detector = cv::xfeatures2d::SURF::create();
      detector->detectAndCompute(queryImg, cv::noArray(), kpA, desA);
      detector->detectAndCompute(trainImg, cv::noArray(), kpB, desB);
   }
   else if(descriptorType == "SIFT")
   {
      queryImg.convertTo(queryImg, CV_8U);
      trainImg.convertTo(trainImg, CV_8U);

      cv::Ptr<cv::xfeatures2d::SIFT> detector = cv::xfeatures2d::SIFT::create();
      detector->detectAndCompute(queryImg, cv::noArray(), kpA, desA);
      detector->detectAndCompute(trainImg, cv::noArray(), kpB, desB);
   }
   else
   {
      std::clog << MODULE << " WARNING: No such descriptor as " << descriptorType << "\n";
      return m_tile;
   }

   // Get the DPoints using the appropriate matcher.
   std::vector< std::vector<cv::DMatch> > weakMatchs;
   if(!(desA.empty() || desB.empty()))
   {
      std::string matcherType = config.getParameter("matcher").asString();
      uint k = config.getParameter("k").asUint();
      if (kpA.size() < k)
         k = kpA.size();
      transform(matcherType.begin(), matcherType.end(), matcherType.begin(),::toupper);

      if(matcherType == "FLANN")
      {
         if(desA.type()!=CV_32F)
            desA.convertTo(desA, CV_32F);
         if(desB.type()!=CV_32F)
            desB.convertTo(desB, CV_32F);
         cv::FlannBasedMatcher matcher;
         matcher.knnMatch(desA, desB, weakMatchs, k);
      }
      else if(matcherType == "BF")
      {
         std::clog << MODULE << " WARNING: BF NOT YET IMPLEMENTED\n";
         return m_tile;
      }
      else
      {
         std::clog << MODULE << " WARNING: No such matcher as " << matcherType << "\n";
         return m_tile;
      }
   }

   int leastDistance = INT_MAX;
   int maxDistance = 0;

   // Find the highest distance to compute the relative confidence of each match
   for (size_t i = 0; i < weakMatchs.size(); ++i)
   {
      for (size_t j = 0; j < weakMatchs[i].size(); ++j)
      {
         if (leastDistance > weakMatchs[i][j].distance)
            leastDistance = weakMatchs[i][j].distance;
         if (maxDistance < weakMatchs[i][j].distance)
            maxDistance = weakMatchs[i][j].distance;
      }
   }

   std::vector< std::vector<cv::DMatch> > strongMatches;
   for(size_t i = 0; i < weakMatchs.size(); ++i)
   {
      std::vector<cv::DMatch> temp;
      for(size_t j = 0; j < weakMatchs[i].size(); ++j)
      {
         if(weakMatchs[i][j].distance < ((maxDistance-leastDistance)*.2+leastDistance))
            temp.push_back(weakMatchs[i][j]);
      }
      if(temp.size()>0) strongMatches.push_back(temp);
   }

   // Sort the matches in order of strength (i.e., confidence) using stl map:
   map<double, shared_ptr<AutoTiePoint> > tpMap;

   // Convert the openCV match points to something Atp could understand.
   string sid(""); // Leave blank to have it auto-assigned by CorrelationTiePoint constructor
   for (size_t i = 0; i < strongMatches.size(); ++i)
   {
      shared_ptr<AutoTiePoint> atp (new AutoTiePoint(this, sid));
      cv::KeyPoint cv_A = kpA[(strongMatches[i][0]).queryIdx];
      cv::KeyPoint cv_B;

      ossimDpt refImgPt (refRect.ul().x + cv_A.pt.x, refRect.ul().y + cv_A.pt.y);
      atp->setRefImagePt(refImgPt);

      // Create the match points
      double strength = 0;
      for (size_t j = 0; j < strongMatches[i].size(); ++j)
      {
         cv_B = kpB[(strongMatches[i][j]).trainIdx];
         ossimDpt cmpImgPt (cmpRect.ul().x + cv_B.pt.x, cmpRect.ul().y + cv_B.pt.y);
         double strength_j = 1.0 - (strongMatches[i][j].distance-leastDistance)/maxDistance;
         if (strength_j > strength)
            strength = strength_j;
         atp->addImageMatch(cmpImgPt, strength_j);
      }
      tpMap.insert(pair<double, shared_ptr<AutoTiePoint> >(strength, atp));

      sid.clear();
   }

   if (config.diagnosticLevel(2))
      clog<<MODULE<<"Before filtering, num matches in tile = "<<strongMatches.size()<<endl;

   // Now skim off the best matches and copy them to the list being returned:
   unsigned int N = config.getParameter("numFeaturesPerTile").asUint();
   unsigned int n = 0;
   map<double, shared_ptr<AutoTiePoint> >::iterator tp_iter = tpMap.begin();
   while ((tp_iter != tpMap.end()) && (n < N))
   {
      m_tiePoints.push_back(tp_iter->second);
      tp_iter++;
      n++;
   }

   if (config.diagnosticLevel(2))
      clog<<MODULE<<"After capping to max num features ("<<N<<"), num TPs in tile = "<<n<<endl;

   return m_tile;
}

}
<commit_msg>Fixed map key ordering for TP strengths<commit_after>//**************************************************************************************************
//
//     OSSIM Open Source Geospatial Data Processing Library
//     See top level LICENSE.txt file for license information
//
//**************************************************************************************************

#include "ossimDescriptorSource.h"
#include "../AtpOpenCV.h"
#include <ossim/imaging/ossimImageData.h>
#include <ossim/base/ossimKeywordlist.h>
#include <ossim/base/ossimConstants.h>
#include <ossim/imaging/ossimImageDataFactory.h>
#include <ossim/projection/ossimSensorModel.h>

#include <opencv2/opencv.hpp>
#include <opencv2/features2d/features2d.hpp>
#include <opencv2/highgui/highgui.hpp>
#include <opencv2/xfeatures2d.hpp>

namespace ATP
{
static const int DEFAULT_CMP_PATCH_SIZING_FACTOR = 2;
static const double DEFAULT_NOMINAL_POSITION_ERROR = 50; // meters

ossimDescriptorSource::ossimDescriptorSource()
{
}

ossimDescriptorSource::ossimDescriptorSource(ossimConnectableObject::ConnectableObjectList& inputSources)
: AtpTileSource(inputSources)
{
   initialize();
}

ossimDescriptorSource::ossimDescriptorSource(AtpGeneratorBase* generator)
: AtpTileSource(generator)
{
}

ossimDescriptorSource::~ossimDescriptorSource()
{
}

void ossimDescriptorSource::initialize()
{
   // Base class initializes ref and cmp chain datat members and associated IVTs. Subsequent call
   // to base class setViewGeom() will initialize the associated IVTs:
   AtpTileSource::initialize();
}

ossimRefPtr<ossimImageData> ossimDescriptorSource::getTile(const ossimIrect& tileRect,
                                                            ossim_uint32 resLevel)
{
   static const char* MODULE = "ossimDescriptorSource::getTile()  ";
   AtpConfig& config = AtpConfig::instance();

   if (config.diagnosticLevel(2))
      clog<<"\n\n"<< MODULE << " -- tileRect: "<<tileRect<<endl;
   m_tiePoints.clear();

   if(!m_tile.get())
   {
      // try to initialize
      initialize();
      if(!m_tile.get()){
         clog << MODULE << " ERROR: could not initialize tile\n";
         return m_tile;
      }
   }

   // Make sure there are at least two images as input.
   if(getNumberOfInputs() < 2)
   {
      clog << MODULE << " ERROR: wrong number of inputs " << getNumberOfInputs() << " when expecting at least 2 \n";
      return 0;
   }

   // The tileRect passed in is in a common map-projected view space. Need to transform the rect
   // into image space for both ref and cmp images:
   ossimIrect refRect (m_refIVT->getViewToImageBounds(tileRect));
   ossimIrect cmpRect (m_cmpIVT->getViewToImageBounds(tileRect));

   // Retrieve both the ref and cmp image data
   ossimRefPtr<ossimImageData> ref_tile = m_refChain->getTile(refRect, resLevel);
   if (ref_tile->getDataObjectStatus() == OSSIM_EMPTY)
   {
      clog << MODULE << " ERROR: could not get REF tile with rect " << refRect << "\n";
      return m_tile;
   }
   if (config.diagnosticLevel(5))
      ref_tile->write("REF_TILE.RAS");

   ossimRefPtr<ossimImageData> cmp_tile = m_cmpChain->getTile(cmpRect, resLevel);
   if (cmp_tile->getDataObjectStatus() == OSSIM_EMPTY)
   {
      clog << MODULE << " ERROR: could not get CMP tile with rect " << cmpRect << "\n";
      return m_tile;
   }
   if (config.diagnosticLevel(5))
      cmp_tile->write("CMP_TILE.RAS");

   m_tile = ref_tile;

   // Convert both into OpenCV Mat objects using the Ipl image.
   IplImage* refImage = convertToIpl32(ref_tile.get());
   IplImage* cmpImage = convertToIpl32(cmp_tile.get());
   cv::Mat queryImg = cv::cvarrToMat(refImage);
   cv::Mat trainImg = cv::cvarrToMat(cmpImage);

   // Get the KeyPoints using appropriate descriptor.
   std::vector<cv::KeyPoint> kpA;
   std::vector<cv::KeyPoint> kpB;
   cv::Mat desA;
   cv::Mat desB;

   std::string descriptorType = config.getParameter("descriptor").asString();
   transform(descriptorType.begin(), descriptorType.end(), descriptorType.begin(),::toupper);
   if(descriptorType == "AKAZE")
   {
      cv::Ptr<cv::AKAZE> detector = cv::AKAZE::create();
      detector->detectAndCompute(queryImg, cv::noArray(), kpA, desA);
      detector->detectAndCompute(trainImg, cv::noArray(), kpB, desB);
   }
   else if(descriptorType == "KAZE")
   {
      cv::Ptr<cv::KAZE> detector = cv::KAZE::create();
      detector->detectAndCompute(queryImg, cv::noArray(), kpA, desA);
      detector->detectAndCompute(trainImg, cv::noArray(), kpB, desB);
   }
   else if(descriptorType == "ORB")
   {
      // For some reason orb wants multiple channel mats so fake it.
      if (queryImg.channels() == 1)
      {
         std::vector<cv::Mat> channels;
         channels.push_back(queryImg);
         channels.push_back(queryImg);
         channels.push_back(queryImg);
         cv::merge(channels, queryImg);
      }

      if (trainImg.channels() == 1)
      {
         std::vector<cv::Mat> channels;
         channels.push_back(trainImg);
         channels.push_back(trainImg);
         channels.push_back(trainImg);
         cv::merge(channels, trainImg);
      }

      cv::Ptr<cv::ORB> detector = cv::ORB::create();
      detector->detectAndCompute(queryImg, cv::noArray(), kpA, desA);
      detector->detectAndCompute(trainImg, cv::noArray(), kpB, desB);
   }
   else if(descriptorType == "SURF")
   {
      queryImg.convertTo(queryImg, CV_8U);
      trainImg.convertTo(trainImg, CV_8U);

      cv::Ptr<cv::xfeatures2d::SURF> detector = cv::xfeatures2d::SURF::create();
      detector->detectAndCompute(queryImg, cv::noArray(), kpA, desA);
      detector->detectAndCompute(trainImg, cv::noArray(), kpB, desB);
   }
   else if(descriptorType == "SIFT")
   {
      queryImg.convertTo(queryImg, CV_8U);
      trainImg.convertTo(trainImg, CV_8U);

      cv::Ptr<cv::xfeatures2d::SIFT> detector = cv::xfeatures2d::SIFT::create();
      detector->detectAndCompute(queryImg, cv::noArray(), kpA, desA);
      detector->detectAndCompute(trainImg, cv::noArray(), kpB, desB);
   }
   else
   {
      std::clog << MODULE << " WARNING: No such descriptor as " << descriptorType << "\n";
      return m_tile;
   }

   // Get the DPoints using the appropriate matcher.
   std::vector< std::vector<cv::DMatch> > weakMatchs;
   if(!(desA.empty() || desB.empty()))
   {
      std::string matcherType = config.getParameter("matcher").asString();
      uint k = config.getParameter("k").asUint();
      if (kpA.size() < k)
         k = kpA.size();
      transform(matcherType.begin(), matcherType.end(), matcherType.begin(),::toupper);

      if(matcherType == "FLANN")
      {
         if(desA.type()!=CV_32F)
            desA.convertTo(desA, CV_32F);
         if(desB.type()!=CV_32F)
            desB.convertTo(desB, CV_32F);
         cv::FlannBasedMatcher matcher;
         matcher.knnMatch(desA, desB, weakMatchs, k);
      }
      else if(matcherType == "BF")
      {
         std::clog << MODULE << " WARNING: BF NOT YET IMPLEMENTED\n";
         return m_tile;
      }
      else
      {
         std::clog << MODULE << " WARNING: No such matcher as " << matcherType << "\n";
         return m_tile;
      }
   }

   int leastDistance = INT_MAX;
   int maxDistance = 0;

   // Find the highest distance to compute the relative confidence of each match
   for (size_t i = 0; i < weakMatchs.size(); ++i)
   {
      for (size_t j = 0; j < weakMatchs[i].size(); ++j)
      {
         if (leastDistance > weakMatchs[i][j].distance)
            leastDistance = weakMatchs[i][j].distance;
         if (maxDistance < weakMatchs[i][j].distance)
            maxDistance = weakMatchs[i][j].distance;
      }
   }

   std::vector< std::vector<cv::DMatch> > strongMatches;
   for(size_t i = 0; i < weakMatchs.size(); ++i)
   {
      std::vector<cv::DMatch> temp;
      for(size_t j = 0; j < weakMatchs[i].size(); ++j)
      {
         if(weakMatchs[i][j].distance < ((maxDistance-leastDistance)*.2+leastDistance))
            temp.push_back(weakMatchs[i][j]);
      }
      if(temp.size()>0) strongMatches.push_back(temp);
   }

   // Sort the matches in order of strength (i.e., confidence) using stl map:
   map<double, shared_ptr<AutoTiePoint> > tpMap;

   // Convert the openCV match points to something Atp could understand.
   string sid(""); // Leave blank to have it auto-assigned by CorrelationTiePoint constructor
   for (size_t i = 0; i < strongMatches.size(); ++i)
   {
      shared_ptr<AutoTiePoint> atp (new AutoTiePoint(this, sid));
      cv::KeyPoint cv_A = kpA[(strongMatches[i][0]).queryIdx];
      cv::KeyPoint cv_B;

      ossimDpt refImgPt (refRect.ul().x + cv_A.pt.x, refRect.ul().y + cv_A.pt.y);
      atp->setRefImagePt(refImgPt);

      // Create the match points
      double strength = 0;
      for (size_t j = 0; j < strongMatches[i].size(); ++j)
      {
         cv_B = kpB[(strongMatches[i][j]).trainIdx];
         ossimDpt cmpImgPt (cmpRect.ul().x + cv_B.pt.x, cmpRect.ul().y + cv_B.pt.y);
         double strength_j = 1.0 - (strongMatches[i][j].distance-leastDistance)/maxDistance;
         if (strength_j > strength)
            strength = strength_j;
         atp->addImageMatch(cmpImgPt, strength_j);
      }

      // Insert into sorted map using one's complement as key since in ascending order:
      tpMap.insert(pair<double, shared_ptr<AutoTiePoint> >(1.0-strength, atp));

      sid.clear();
   }

   if (config.diagnosticLevel(2))
      clog<<MODULE<<"Before filtering, num matches in tile = "<<strongMatches.size()<<endl;

   // Now skim off the best matches and copy them to the list being returned:
   unsigned int N = config.getParameter("numFeaturesPerTile").asUint();
   unsigned int n = 0;
   map<double, shared_ptr<AutoTiePoint> >::iterator tp_iter = tpMap.begin();
   while ((tp_iter != tpMap.end()) && (n < N))
   {
      m_tiePoints.push_back(tp_iter->second);
      tp_iter++;
      n++;
   }

   if (config.diagnosticLevel(2))
      clog<<MODULE<<"After capping to max num features ("<<N<<"), num TPs in tile = "<<n<<endl;

   return m_tile;
}

}
<|endoftext|>