<commit_before>/*  This file is part of the KDE project.

Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).

This library is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation, either version 2.1 or 3 of the License.

This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU Lesser General Public License for more details.

You should have received a copy of the GNU Lesser General Public License
along with this library.  If not, see <http://www.gnu.org/licenses/>.

*/

#include <QUrl>

#include "audioplayer.h"
#include "utils.h"

QT_BEGIN_NAMESPACE

using namespace Phonon;
using namespace Phonon::MMF;

//-----------------------------------------------------------------------------
// Constructor / destructor
//-----------------------------------------------------------------------------

MMF::AudioPlayer::AudioPlayer() : m_player(0)
{
    construct();
}

MMF::AudioPlayer::AudioPlayer(const AbstractPlayer& player)
        : AbstractMediaPlayer(player)
        , m_player(0)
{
    construct();
}

void MMF::AudioPlayer::construct()
{
    TRACE_CONTEXT(AudioPlayer::AudioPlayer, EAudioApi);
    TRACE_ENTRY_0();

    // TODO: is this the correct way to handle errors which occur when
    // creating a Symbian object in the constructor of a Qt object?
    TRAPD(err, m_player = CPlayerType::NewL(*this, 0, EMdaPriorityPreferenceNone));
    if (KErrNone != err) {
        changeState(ErrorState);
    }

    TRACE_EXIT_0();
}

MMF::AudioPlayer::~AudioPlayer()
{
    TRACE_CONTEXT(AudioPlayer::~AudioPlayer, EAudioApi);
    TRACE_ENTRY_0();

    delete m_player;

    TRACE_EXIT_0();
}

//-----------------------------------------------------------------------------
// Public API
//-----------------------------------------------------------------------------

void MMF::AudioPlayer::doPlay()
{
    m_player->Play();
}

void MMF::AudioPlayer::doPause()
{
    m_player->Pause();
}

void MMF::AudioPlayer::doStop()
{
    m_player->Stop();
}

void MMF::AudioPlayer::doSeek(qint64 ms)
{
    m_player->SetPosition(TTimeIntervalMicroSeconds(ms * 1000));
}

int MMF::AudioPlayer::setDeviceVolume(int mmfVolume)
{
    /* In SDK 3.1, this function is void. */
#if !defined(__SERIES60_31__)
    return m_player->SetVolume(mmfVolume);
#else
    m_player->SetVolume(mmfVolume);
    return KErrNone;
#endif
}

int MMF::AudioPlayer::openFile(RFile& file)
{
    TRAPD(err, m_player->OpenFileL(file));

#ifdef QT_PHONON_MMF_AUDIO_DRM
    if (KErrNone == err) {
        // There appears to be a bug in the CDrmPlayerUtility implementation (at least
        // in S60 5.x) whereby the player does not check whether the loading observer
        // pointer is null before dereferencing it.  Therefore we must register for
        // loading notification, even though we do nothing in the callback functions.
        m_player->RegisterForAudioLoadingNotification(*this);
    }
#endif

    return err;
}

void MMF::AudioPlayer::close()
{
    m_player->Close();
}

bool MMF::AudioPlayer::hasVideo() const
{
    return false;
}

qint64 MMF::AudioPlayer::currentTime() const
{
    TRACE_CONTEXT(AudioPlayer::currentTime, EAudioApi);

    TTimeIntervalMicroSeconds us;
    const TInt err = m_player->GetPosition(us);

    qint64 result = 0;

    if (KErrNone == err) {
        result = toMilliSeconds(us);
    } else {
        TRACE("GetPosition err %d", err);

        // If we don't cast away constness here, we simply have to ignore
        // the error.
        const_cast<AudioPlayer*>(this)->setError(NormalError);
    }

    return result;
}

qint64 MMF::AudioPlayer::totalTime() const
{
    return toMilliSeconds(m_player->Duration());
}

//-----------------------------------------------------------------------------
// Symbian multimedia client observer callbacks
//-----------------------------------------------------------------------------

#ifdef QT_PHONON_MMF_AUDIO_DRM
void MMF::AudioPlayer::MdapcInitComplete(TInt aError,
        const TTimeIntervalMicroSeconds &)
#else
void MMF::AudioPlayer::MapcInitComplete(TInt aError,
                                        const TTimeIntervalMicroSeconds &)
#endif
{
    TRACE_CONTEXT(AudioPlayer::MapcInitComplete, EAudioInternal);
    TRACE_ENTRY("state %d error %d", state(), aError);

    __ASSERT_ALWAYS(LoadingState == state(), Utils::panic(InvalidStatePanic));

    if (KErrNone == aError) {
        maxVolumeChanged(m_player->MaxVolume());

        emit totalTimeChanged(totalTime());
        changeState(StoppedState);
    } else {
        // TODO: set different error states according to value of aError?
        setError(NormalError);
    }

    TRACE_EXIT_0();
}

#ifdef QT_PHONON_MMF_AUDIO_DRM
void MMF::AudioPlayer::MdapcPlayComplete(TInt aError)
#else
void MMF::AudioPlayer::MapcPlayComplete(TInt aError)
#endif
{
    TRACE_CONTEXT(AudioPlayer::MapcPlayComplete, EAudioInternal);
    TRACE_ENTRY("state %d error %d", state(), aError);

    stopTickTimer();

    if (KErrNone == aError) {
        changeState(StoppedState);
        // TODO: move on to m_nextSource
    } else {
        // TODO: do something with aError?
        setError(NormalError);
    }

    /*
        if(aError == KErrNone) {
            if(m_nextSource.type() == MediaSource::Empty) {
                emit finished();
            } else {
                setSource(m_nextSource);
                m_nextSource = MediaSource();
            }

            changeState(StoppedState);
        }
        else {
            m_error = NormalError;
            changeState(ErrorState);
        }
    */

    TRACE_EXIT_0();
}

CPlayerType *MMF::AudioPlayer::player() const
{
    return m_player;
}

#ifdef QT_PHONON_MMF_AUDIO_DRM
void MMF::AudioPlayer::MaloLoadingStarted()
{

}

void MMF::AudioPlayer::MaloLoadingComplete()
{

}
#endif // QT_PHONON_MMF_AUDIO_DRM

QT_END_NAMESPACE

<commit_msg>Do runtime check for SetVolume.<commit_after>/*  This file is part of the KDE project.

Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).

This library is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation, either version 2.1 or 3 of the License.

This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU Lesser General Public License for more details.

You should have received a copy of the GNU Lesser General Public License
along with this library.  If not, see <http://www.gnu.org/licenses/>.

*/

#include <QUrl>

#include "audioplayer.h"
#include "utils.h"

QT_BEGIN_NAMESPACE

using namespace Phonon;
using namespace Phonon::MMF;

//-----------------------------------------------------------------------------
// Constructor / destructor
//-----------------------------------------------------------------------------

MMF::AudioPlayer::AudioPlayer() : m_player(0)
{
    construct();
}

MMF::AudioPlayer::AudioPlayer(const AbstractPlayer& player)
        : AbstractMediaPlayer(player)
        , m_player(0)
{
    construct();
}

void MMF::AudioPlayer::construct()
{
    TRACE_CONTEXT(AudioPlayer::AudioPlayer, EAudioApi);
    TRACE_ENTRY_0();

    // TODO: is this the correct way to handle errors which occur when
    // creating a Symbian object in the constructor of a Qt object?
    TRAPD(err, m_player = CPlayerType::NewL(*this, 0, EMdaPriorityPreferenceNone));
    if (KErrNone != err) {
        changeState(ErrorState);
    }

    TRACE_EXIT_0();
}

MMF::AudioPlayer::~AudioPlayer()
{
    TRACE_CONTEXT(AudioPlayer::~AudioPlayer, EAudioApi);
    TRACE_ENTRY_0();

    delete m_player;

    TRACE_EXIT_0();
}

//-----------------------------------------------------------------------------
// Public API
//-----------------------------------------------------------------------------

void MMF::AudioPlayer::doPlay()
{
    m_player->Play();
}

void MMF::AudioPlayer::doPause()
{
    m_player->Pause();
}

void MMF::AudioPlayer::doStop()
{
    m_player->Stop();
}

void MMF::AudioPlayer::doSeek(qint64 ms)
{
    m_player->SetPosition(TTimeIntervalMicroSeconds(ms * 1000));
}

int MMF::AudioPlayer::setDeviceVolume(int mmfVolume)
{
    /* In SDK 3.1, SetVolume() returns void. If we're compiling against
     * 3.1, we handle it with ifdefs. However, if we compile against a later
     * SDK but are _running_ against 3.1, we avoid returning from an undefined
     * stack by doing a runtime check of the SDK version. */
#if !defined(__SERIES60_31__)
    const int err = m_player->SetVolume(mmfVolume);
    if (QSysInfo::s60Version() > QSysInfo::SV_S60_3_1)
        return err;
    else
        return KErrNone;
 #else
     m_player->SetVolume(mmfVolume);
     return KErrNone;
#endif
}

int MMF::AudioPlayer::openFile(RFile& file)
{
    TRAPD(err, m_player->OpenFileL(file));

#ifdef QT_PHONON_MMF_AUDIO_DRM
    if (KErrNone == err) {
        // There appears to be a bug in the CDrmPlayerUtility implementation (at least
        // in S60 5.x) whereby the player does not check whether the loading observer
        // pointer is null before dereferencing it.  Therefore we must register for
        // loading notification, even though we do nothing in the callback functions.
        m_player->RegisterForAudioLoadingNotification(*this);
    }
#endif

    return err;
}

void MMF::AudioPlayer::close()
{
    m_player->Close();
}

bool MMF::AudioPlayer::hasVideo() const
{
    return false;
}

qint64 MMF::AudioPlayer::currentTime() const
{
    TRACE_CONTEXT(AudioPlayer::currentTime, EAudioApi);

    TTimeIntervalMicroSeconds us;
    const TInt err = m_player->GetPosition(us);

    qint64 result = 0;

    if (KErrNone == err) {
        result = toMilliSeconds(us);
    } else {
        TRACE("GetPosition err %d", err);

        // If we don't cast away constness here, we simply have to ignore
        // the error.
        const_cast<AudioPlayer*>(this)->setError(NormalError);
    }

    return result;
}

qint64 MMF::AudioPlayer::totalTime() const
{
    return toMilliSeconds(m_player->Duration());
}

//-----------------------------------------------------------------------------
// Symbian multimedia client observer callbacks
//-----------------------------------------------------------------------------

#ifdef QT_PHONON_MMF_AUDIO_DRM
void MMF::AudioPlayer::MdapcInitComplete(TInt aError,
        const TTimeIntervalMicroSeconds &)
#else
void MMF::AudioPlayer::MapcInitComplete(TInt aError,
                                        const TTimeIntervalMicroSeconds &)
#endif
{
    TRACE_CONTEXT(AudioPlayer::MapcInitComplete, EAudioInternal);
    TRACE_ENTRY("state %d error %d", state(), aError);

    __ASSERT_ALWAYS(LoadingState == state(), Utils::panic(InvalidStatePanic));

    if (KErrNone == aError) {
        maxVolumeChanged(m_player->MaxVolume());

        emit totalTimeChanged(totalTime());
        changeState(StoppedState);
    } else {
        // TODO: set different error states according to value of aError?
        setError(NormalError);
    }

    TRACE_EXIT_0();
}

#ifdef QT_PHONON_MMF_AUDIO_DRM
void MMF::AudioPlayer::MdapcPlayComplete(TInt aError)
#else
void MMF::AudioPlayer::MapcPlayComplete(TInt aError)
#endif
{
    TRACE_CONTEXT(AudioPlayer::MapcPlayComplete, EAudioInternal);
    TRACE_ENTRY("state %d error %d", state(), aError);

    stopTickTimer();

    if (KErrNone == aError) {
        changeState(StoppedState);
        // TODO: move on to m_nextSource
    } else {
        // TODO: do something with aError?
        setError(NormalError);
    }

    /*
        if(aError == KErrNone) {
            if(m_nextSource.type() == MediaSource::Empty) {
                emit finished();
            } else {
                setSource(m_nextSource);
                m_nextSource = MediaSource();
            }

            changeState(StoppedState);
        }
        else {
            m_error = NormalError;
            changeState(ErrorState);
        }
    */

    TRACE_EXIT_0();
}

CPlayerType *MMF::AudioPlayer::player() const
{
    return m_player;
}

#ifdef QT_PHONON_MMF_AUDIO_DRM
void MMF::AudioPlayer::MaloLoadingStarted()
{

}

void MMF::AudioPlayer::MaloLoadingComplete()
{

}
#endif // QT_PHONON_MMF_AUDIO_DRM

QT_END_NAMESPACE

<|endoftext|>


<commit_before>//Copyright (c) 2019 Ultimaker B.V.

#include "BeadingOrderOptimizer.h"

#include <iterator>
#include <unordered_map>
#include <vector>
#include <list>

namespace arachne
{

void BeadingOrderOptimizer::optimize(const std::vector<ExtrusionSegment>& segments, std::vector<std::vector<std::vector<ExtrusionJunction>>>& result_polygons_per_index, std::vector<std::vector<std::vector<ExtrusionJunction>>>& result_polylines_per_index)
{
    BeadingOrderOptimizer optimizer(segments);
    optimizer.connect(result_polygons_per_index);
    optimizer.reduceIntersectionOverlap(result_polygons_per_index);
    optimizer.transferUnconnectedPolylines(result_polygons_per_index, result_polylines_per_index);
}

void BeadingOrderOptimizer::connect(std::vector<std::vector<std::vector<ExtrusionJunction>>>& result_polygons_per_index)
{
    debugCheck();
    for (const ExtrusionSegment& segment : segments)
    {
        if (segment.from.p == segment.to.p)
        {
            assert(segment.from.w == segment.to.w);
            continue;
        }

        assert(segment.from.perimeter_index == segment.to.perimeter_index);
        coord_t inset_idx = segment.from.perimeter_index;
        std::list<Polyline>& polylines = segment.is_odd? odd_polylines : even_polylines;
        std::unordered_map<Point, PolylineEndRef>& polyline_end_points = segment.is_odd? odd_polyline_end_points : even_polyline_end_points;

        auto start_it = polyline_end_points.find(segment.from.p);
        auto end_it = polyline_end_points.find(segment.to.p);

        bool connect_start = start_it != polyline_end_points.end();
        bool connect_end = end_it != polyline_end_points.end();
        debugCheck();
        if (!connect_start && !connect_end)
        {
            polylines.emplace_back(inset_idx);
            std::list<ExtrusionJunction>& junctions = polylines.back().junctions;
            junctions.emplace_front(segment.from);
            junctions.emplace_back(segment.to);
            polyline_end_points.emplace(segment.from.p, PolylineEndRef(inset_idx, --polylines.end(), true));
            polyline_end_points.emplace(segment.to.p, PolylineEndRef(inset_idx, --polylines.end(), false));
        }
        else if (connect_start && !connect_end)
        {
            PolylineEndRef ref = start_it->second;
            if (ref.front)
            {
                ref.polyline->junctions.emplace_front(segment.to);
            }
            else
            {
                ref.polyline->junctions.emplace_back(segment.to);
            }
            polyline_end_points.erase(start_it);
            polyline_end_points.emplace(segment.to.p, ref);
        }
        else if (!connect_start && connect_end)
        {
            PolylineEndRef ref = end_it->second;
            if (ref.front)
            {
                ref.polyline->junctions.emplace_front(segment.from);
            }
            else
            {
                ref.polyline->junctions.emplace_back(segment.from);
            }
            polyline_end_points.erase(end_it);
            polyline_end_points.emplace(segment.from.p, ref);
        }
        else // if (connect_start && connect_end)
        {
            PolylineEndRef start_ref = start_it->second;
            PolylineEndRef end_ref = end_it->second;

            std::list<ExtrusionJunction>& result_junctions = start_ref.polyline->junctions;

            assert(start_it != end_it);
            polyline_end_points.erase(start_it);
            polyline_end_points.erase(end_it);
            if (&*start_ref.polyline != &*end_ref.polyline)
            {
                polyline_end_points.erase((start_ref.front)? start_ref.polyline->junctions.back().p : start_ref.polyline->junctions.front().p);
                polyline_end_points.erase((end_ref.front)? end_ref.polyline->junctions.back().p : end_ref.polyline->junctions.front().p);
                std::list<ExtrusionJunction>::iterator insert_position = start_ref.front? result_junctions.begin() : result_junctions.end();
                if (end_ref.front == start_ref.front)
                {
                    result_junctions.insert(insert_position, end_ref.polyline->junctions.rbegin(), end_ref.polyline->junctions.rend());
                }
                else
                {
                    result_junctions.insert(insert_position, end_ref.polyline->junctions.begin(), end_ref.polyline->junctions.end());
                }
                polyline_end_points.emplace(result_junctions.front().p, PolylineEndRef(start_ref.inset_idx, start_ref.polyline, true));
                polyline_end_points.emplace(result_junctions.back().p, PolylineEndRef(start_ref.inset_idx, start_ref.polyline, false));
                polylines.erase(end_ref.polyline);
            }
            else // if start_ref.polyline == end_ref.polyline
            {
                polyline_end_points.erase((start_ref.front)? start_ref.polyline->junctions.back().p : start_ref.polyline->junctions.front().p);
                polyline_end_points.erase((end_ref.front)? end_ref.polyline->junctions.back().p : end_ref.polyline->junctions.front().p);
                // close polygon and add it to the results
                result_polygons_per_index.resize(std::max(result_polygons_per_index.size(), static_cast<size_t>(start_ref.inset_idx + 1)));
                result_polygons_per_index[start_ref.inset_idx].emplace_back(result_junctions.begin(), result_junctions.end());
                polylines.erase(start_ref.polyline);
            }
        }
    }
    debugCheck();
}

void BeadingOrderOptimizer::reduceIntersectionOverlap(std::vector<std::vector<std::vector<ExtrusionJunction>>>& polygons_per_index)
{
    for (Polyline& polyline : odd_polylines)
    {
        reduceIntersectionOverlap(polyline, polyline.junctions.begin(), polyline.inset_idx, polygons_per_index);
        reduceIntersectionOverlap(polyline, polyline.junctions.rbegin(), polyline.inset_idx, polygons_per_index);
    }
}

template<typename directional_iterator>
void BeadingOrderOptimizer::reduceIntersectionOverlap(Polyline& polyline, directional_iterator polyline_start_it, coord_t inset_idx, std::vector<std::vector<std::vector<ExtrusionJunction>>>& polygons_per_index)
{
    ExtrusionJunction& start_junction = *polyline_start_it;
    ExtrusionJunction* intersecting_junction = nullptr;
    for (std::vector<ExtrusionJunction>& polygon : polygons_per_index[inset_idx])
    {
        for (ExtrusionJunction& junction : polygon)
        {
            if (junction.p == start_junction.p)
            {
                assert(junction.w == start_junction.w);
                intersecting_junction = &junction;
                break;
            }
        }
        if (intersecting_junction) break;
    }
    if (!intersecting_junction) return;

    reduceIntersectionOverlap(polyline, polyline_start_it, 0, intersecting_junction->w / 2 * (1.0 - intersection_overlap));
}

template<typename directional_iterator>
void BeadingOrderOptimizer::reduceIntersectionOverlap(Polyline& polyline, directional_iterator polyline_it, coord_t traveled_dist, coord_t reduction_length)
{
    ExtrusionJunction& start_junction = *polyline_it;
    polyline_it++;
    if (isEnd(polyline_it, polyline))
    {
        return;
    }
    ExtrusionJunction& next_junction = *polyline_it;
    Point a = start_junction.p;
    Point b = next_junction.p;
    Point ab = b - a;
    coord_t length = vSize(ab);

    coord_t total_reduction_length = reduction_length + start_junction.w / 2;

    if (traveled_dist + length > total_reduction_length)
    {
        Point mid1 = a + ab * std::max(static_cast<coord_t>(0), std::min(length, (total_reduction_length - traveled_dist) / length));
//         Point mid2 = mid1; // a + ab * std::min(reduction_length + 10, length) / length;
        std::list<ExtrusionJunction>::iterator forward_it = getInsertPosIt( polyline_it );
        coord_t mid_w = start_junction.w + (next_junction.w - start_junction.w) * reduction_length / length;
        polyline.junctions.insert(forward_it, ExtrusionJunction(mid1, mid_w, start_junction.perimeter_index));
//         polyline.junctions.insert(forward_it, ExtrusionJunction(mid1, 0, start_junction.perimeter_index));
    }
    else
    {
        // NOTE: polyline_start_it was already increased
        reduceIntersectionOverlap(polyline, polyline_it, traveled_dist + length, reduction_length);
    }

    if (polyline.junctions.size() > 1)
    {
        polyline.junctions.erase(getSelfPosIt(--polyline_it));
    }
    if (polyline.junctions.size() == 1)
    {
        polyline.junctions.emplace_back(polyline.junctions.front());
        polyline.junctions.back().p += Point(1,1);
    }
}

template<>
bool BeadingOrderOptimizer::isEnd(std::list<ExtrusionJunction>::iterator it, Polyline& polyline)
{
    return it == polyline.junctions.end();
}

template<>
bool BeadingOrderOptimizer::isEnd(std::list<ExtrusionJunction>::reverse_iterator it, Polyline& polyline)
{
    return it == polyline.junctions.rend();
}

template<>
std::list<ExtrusionJunction>::iterator BeadingOrderOptimizer::getInsertPosIt(std::list<ExtrusionJunction>::iterator it)
{
    return it;
}

template<>
std::list<ExtrusionJunction>::iterator BeadingOrderOptimizer::getInsertPosIt(std::list<ExtrusionJunction>::reverse_iterator it)
{
    return it.base();
}

template<>
std::list<ExtrusionJunction>::iterator BeadingOrderOptimizer::getSelfPosIt(std::list<ExtrusionJunction>::iterator it)
{
    return it;
}

template<>
std::list<ExtrusionJunction>::iterator BeadingOrderOptimizer::getSelfPosIt(std::list<ExtrusionJunction>::reverse_iterator it)
{
    return (++it).base();
}

void BeadingOrderOptimizer::transferUnconnectedPolylines(std::vector<std::vector<std::vector<ExtrusionJunction>>>& result_polygons_per_index, std::vector<std::vector<std::vector<ExtrusionJunction>>>& result_polylines_per_index)
{
    // copy unfinished polylines to result
    result_polylines_per_index.resize(std::max(result_polylines_per_index.size(), even_polylines.size() + odd_polylines.size()));
    for (auto polylines : { even_polylines, odd_polylines })
    {
        for (Polyline& polyline : polylines)
        {
            result_polylines_per_index[polyline.inset_idx].emplace_back(polyline.junctions.begin(), polyline.junctions.end());
        }
    }
}

void BeadingOrderOptimizer::debugCheck()
{
#ifdef DEBUG
    for (auto polylines : { even_polylines, odd_polylines })
    {
        for (Polyline& polyline : polylines)
        {
            for (ExtrusionJunction& junction : polyline.junctions)
            {
                assert(junction.perimeter_index == polyline.inset_idx);
                assert(junction.p.X < 100000 && junction.p.Y < 100000);
                assert(junction.p.X > -100000 && junction.p.Y > -100000);
            }
        }
    }
    for (auto polyline_end_points : { even_polyline_end_points, odd_polyline_end_points })
    {
        for (auto pair : polyline_end_points)
        {
            PolylineEndRef ref = pair.second;
            Point p = pair.first;
            assert(p == ((ref.front)? ref.polyline->junctions.front().p : ref.polyline->junctions.back().p));
            auto find_it = even_polylines.begin();
            for (; find_it != even_polylines.end(); ++find_it)
            {
                if (find_it == ref.polyline) break;
            }
            if (find_it == even_polylines.end())
            {
                for (find_it = odd_polylines.begin(); find_it != odd_polylines.end(); ++find_it)
                {
                    if (find_it == ref.polyline) break;
                }
            }
            assert(find_it != odd_polylines.end());
        }
    }
#endif
};

} // namespace arachne
<commit_msg>reduce intersection overlap when there are 3-way intersection among odd segments<commit_after>//Copyright (c) 2019 Ultimaker B.V.

#include "BeadingOrderOptimizer.h"

#include <iterator>
#include <unordered_map>
#include <vector>
#include <list>

namespace arachne
{

void BeadingOrderOptimizer::optimize(const std::vector<ExtrusionSegment>& segments, std::vector<std::vector<std::vector<ExtrusionJunction>>>& result_polygons_per_index, std::vector<std::vector<std::vector<ExtrusionJunction>>>& result_polylines_per_index)
{
    BeadingOrderOptimizer optimizer(segments);
    optimizer.connect(result_polygons_per_index);
    optimizer.reduceIntersectionOverlap(result_polygons_per_index);
    optimizer.transferUnconnectedPolylines(result_polygons_per_index, result_polylines_per_index);
}

void BeadingOrderOptimizer::connect(std::vector<std::vector<std::vector<ExtrusionJunction>>>& result_polygons_per_index)
{
    debugCheck();
    for (const ExtrusionSegment& segment : segments)
    {
        if (segment.from.p == segment.to.p)
        {
            assert(segment.from.w == segment.to.w);
            continue;
        }

        assert(segment.from.perimeter_index == segment.to.perimeter_index);
        coord_t inset_idx = segment.from.perimeter_index;
        std::list<Polyline>& polylines = segment.is_odd? odd_polylines : even_polylines;
        std::unordered_map<Point, PolylineEndRef>& polyline_end_points = segment.is_odd? odd_polyline_end_points : even_polyline_end_points;

        auto start_it = polyline_end_points.find(segment.from.p);
        auto end_it = polyline_end_points.find(segment.to.p);

        bool connect_start = start_it != polyline_end_points.end();
        bool connect_end = end_it != polyline_end_points.end();
        debugCheck();
        if (!connect_start && !connect_end)
        {
            polylines.emplace_back(inset_idx);
            std::list<ExtrusionJunction>& junctions = polylines.back().junctions;
            junctions.emplace_front(segment.from);
            junctions.emplace_back(segment.to);
            polyline_end_points.emplace(segment.from.p, PolylineEndRef(inset_idx, --polylines.end(), true));
            polyline_end_points.emplace(segment.to.p, PolylineEndRef(inset_idx, --polylines.end(), false));
        }
        else if (connect_start && !connect_end)
        {
            PolylineEndRef ref = start_it->second;
            if (ref.front)
            {
                ref.polyline->junctions.emplace_front(segment.to);
            }
            else
            {
                ref.polyline->junctions.emplace_back(segment.to);
            }
            polyline_end_points.erase(start_it);
            polyline_end_points.emplace(segment.to.p, ref);
        }
        else if (!connect_start && connect_end)
        {
            PolylineEndRef ref = end_it->second;
            if (ref.front)
            {
                ref.polyline->junctions.emplace_front(segment.from);
            }
            else
            {
                ref.polyline->junctions.emplace_back(segment.from);
            }
            polyline_end_points.erase(end_it);
            polyline_end_points.emplace(segment.from.p, ref);
        }
        else // if (connect_start && connect_end)
        {
            PolylineEndRef start_ref = start_it->second;
            PolylineEndRef end_ref = end_it->second;

            std::list<ExtrusionJunction>& result_junctions = start_ref.polyline->junctions;

            assert(start_it != end_it);
            polyline_end_points.erase(start_it);
            polyline_end_points.erase(end_it);
            if (&*start_ref.polyline != &*end_ref.polyline)
            {
                polyline_end_points.erase((start_ref.front)? start_ref.polyline->junctions.back().p : start_ref.polyline->junctions.front().p);
                polyline_end_points.erase((end_ref.front)? end_ref.polyline->junctions.back().p : end_ref.polyline->junctions.front().p);
                std::list<ExtrusionJunction>::iterator insert_position = start_ref.front? result_junctions.begin() : result_junctions.end();
                if (end_ref.front == start_ref.front)
                {
                    result_junctions.insert(insert_position, end_ref.polyline->junctions.rbegin(), end_ref.polyline->junctions.rend());
                }
                else
                {
                    result_junctions.insert(insert_position, end_ref.polyline->junctions.begin(), end_ref.polyline->junctions.end());
                }
                polyline_end_points.emplace(result_junctions.front().p, PolylineEndRef(start_ref.inset_idx, start_ref.polyline, true));
                polyline_end_points.emplace(result_junctions.back().p, PolylineEndRef(start_ref.inset_idx, start_ref.polyline, false));
                polylines.erase(end_ref.polyline);
            }
            else // if start_ref.polyline == end_ref.polyline
            {
                polyline_end_points.erase((start_ref.front)? start_ref.polyline->junctions.back().p : start_ref.polyline->junctions.front().p);
                polyline_end_points.erase((end_ref.front)? end_ref.polyline->junctions.back().p : end_ref.polyline->junctions.front().p);
                // close polygon and add it to the results
                result_polygons_per_index.resize(std::max(result_polygons_per_index.size(), static_cast<size_t>(start_ref.inset_idx + 1)));
                result_polygons_per_index[start_ref.inset_idx].emplace_back(result_junctions.begin(), result_junctions.end());
                polylines.erase(start_ref.polyline);
            }
        }
    }
    debugCheck();
}

void BeadingOrderOptimizer::reduceIntersectionOverlap(std::vector<std::vector<std::vector<ExtrusionJunction>>>& polygons_per_index)
{
    for (Polyline& polyline : odd_polylines)
    {
        reduceIntersectionOverlap(polyline, polyline.junctions.begin(), polyline.inset_idx, polygons_per_index);
        reduceIntersectionOverlap(polyline, polyline.junctions.rbegin(), polyline.inset_idx, polygons_per_index);
    }
}

template<typename directional_iterator>
void BeadingOrderOptimizer::reduceIntersectionOverlap(Polyline& polyline, directional_iterator polyline_start_it, coord_t inset_idx, std::vector<std::vector<std::vector<ExtrusionJunction>>>& polygons_per_index)
{
    ExtrusionJunction& start_junction = *polyline_start_it;
    ExtrusionJunction* intersecting_junction = nullptr;
    for (std::vector<ExtrusionJunction>& polygon : polygons_per_index[inset_idx])
    {
        for (ExtrusionJunction& junction : polygon)
        {
            if (junction.p == start_junction.p)
            {
                assert(junction.w == start_junction.w);
                intersecting_junction = &junction;
                break;
            }
        }
        if (intersecting_junction) break;
    }
    if (!intersecting_junction)
    {
        for (Polyline& other_polyline : odd_polylines)
        {
            if (other_polyline.inset_idx != polyline.inset_idx) continue;

            for (auto junction_it = ++other_polyline.junctions.begin(); junction_it != --other_polyline.junctions.end() && junction_it != other_polyline.junctions.end(); junction_it++)
            { // skip end points, because they would have been connected to this point!
                if (junction_it->p == start_junction.p)
                {
                    intersecting_junction = &*junction_it;
                    break;
                }
            }
            if (intersecting_junction) break;
        }
    }
    if (!intersecting_junction) return;

    reduceIntersectionOverlap(polyline, polyline_start_it, 0, intersecting_junction->w / 2 * (1.0 - intersection_overlap));
}

template<typename directional_iterator>
void BeadingOrderOptimizer::reduceIntersectionOverlap(Polyline& polyline, directional_iterator polyline_it, coord_t traveled_dist, coord_t reduction_length)
{
    ExtrusionJunction& start_junction = *polyline_it;
    polyline_it++;
    if (isEnd(polyline_it, polyline))
    {
        return;
    }
    ExtrusionJunction& next_junction = *polyline_it;
    Point a = start_junction.p;
    Point b = next_junction.p;
    Point ab = b - a;
    coord_t length = vSize(ab);

    coord_t total_reduction_length = reduction_length + start_junction.w / 2;

    if (traveled_dist + length > total_reduction_length)
    {
        Point mid1 = a + ab * std::max(static_cast<coord_t>(0), std::min(length, (total_reduction_length - traveled_dist) / length));
//         Point mid2 = mid1; // a + ab * std::min(reduction_length + 10, length) / length;
        std::list<ExtrusionJunction>::iterator forward_it = getInsertPosIt( polyline_it );
        coord_t mid_w = start_junction.w + (next_junction.w - start_junction.w) * reduction_length / length;
        polyline.junctions.insert(forward_it, ExtrusionJunction(mid1, mid_w, start_junction.perimeter_index));
//         polyline.junctions.insert(forward_it, ExtrusionJunction(mid1, 0, start_junction.perimeter_index));
    }
    else
    {
        // NOTE: polyline_start_it was already increased
        reduceIntersectionOverlap(polyline, polyline_it, traveled_dist + length, reduction_length);
    }

    if (polyline.junctions.size() > 1)
    {
        polyline.junctions.erase(getSelfPosIt(--polyline_it));
    }
    if (polyline.junctions.size() == 1)
    {
        polyline.junctions.emplace_back(polyline.junctions.front());
        polyline.junctions.back().p += Point(1,1);
    }
}

template<>
bool BeadingOrderOptimizer::isEnd(std::list<ExtrusionJunction>::iterator it, Polyline& polyline)
{
    return it == polyline.junctions.end();
}

template<>
bool BeadingOrderOptimizer::isEnd(std::list<ExtrusionJunction>::reverse_iterator it, Polyline& polyline)
{
    return it == polyline.junctions.rend();
}

template<>
std::list<ExtrusionJunction>::iterator BeadingOrderOptimizer::getInsertPosIt(std::list<ExtrusionJunction>::iterator it)
{
    return it;
}

template<>
std::list<ExtrusionJunction>::iterator BeadingOrderOptimizer::getInsertPosIt(std::list<ExtrusionJunction>::reverse_iterator it)
{
    return it.base();
}

template<>
std::list<ExtrusionJunction>::iterator BeadingOrderOptimizer::getSelfPosIt(std::list<ExtrusionJunction>::iterator it)
{
    return it;
}

template<>
std::list<ExtrusionJunction>::iterator BeadingOrderOptimizer::getSelfPosIt(std::list<ExtrusionJunction>::reverse_iterator it)
{
    return (++it).base();
}

void BeadingOrderOptimizer::transferUnconnectedPolylines(std::vector<std::vector<std::vector<ExtrusionJunction>>>& result_polygons_per_index, std::vector<std::vector<std::vector<ExtrusionJunction>>>& result_polylines_per_index)
{
    // copy unfinished polylines to result
    result_polylines_per_index.resize(std::max(result_polylines_per_index.size(), even_polylines.size() + odd_polylines.size()));
    for (auto polylines : { even_polylines, odd_polylines })
    {
        for (Polyline& polyline : polylines)
        {
            result_polylines_per_index[polyline.inset_idx].emplace_back(polyline.junctions.begin(), polyline.junctions.end());
        }
    }
}

void BeadingOrderOptimizer::debugCheck()
{
#ifdef DEBUG
    for (auto polylines : { even_polylines, odd_polylines })
    {
        for (Polyline& polyline : polylines)
        {
            for (ExtrusionJunction& junction : polyline.junctions)
            {
                assert(junction.perimeter_index == polyline.inset_idx);
                assert(junction.p.X < 100000 && junction.p.Y < 100000);
                assert(junction.p.X > -100000 && junction.p.Y > -100000);
            }
        }
    }
    for (auto polyline_end_points : { even_polyline_end_points, odd_polyline_end_points })
    {
        for (auto pair : polyline_end_points)
        {
            PolylineEndRef ref = pair.second;
            Point p = pair.first;
            assert(p == ((ref.front)? ref.polyline->junctions.front().p : ref.polyline->junctions.back().p));
            auto find_it = even_polylines.begin();
            for (; find_it != even_polylines.end(); ++find_it)
            {
                if (find_it == ref.polyline) break;
            }
            if (find_it == even_polylines.end())
            {
                for (find_it = odd_polylines.begin(); find_it != odd_polylines.end(); ++find_it)
                {
                    if (find_it == ref.polyline) break;
                }
            }
            assert(find_it != odd_polylines.end());
        }
    }
#endif
};

} // namespace arachne
<|endoftext|>


<commit_before>//
// Copyright (c) 2017 The nanoFramework project contributors
// Portions Copyright (c) Microsoft Corporation.  All rights reserved.
// See LICENSE file in the project root for full license information.
//

#include "nf_rt_native.h"

static const CLR_RT_MethodHandler method_lookup[] =
{
    Library_nf_rt_native_nanoFramework_Runtime_Native_SystemInfo::GetSystemVersion___STATIC__VOID__BYREF_I4__BYREF_I4__BYREF_I4__BYREF_I4,
    NULL,
    Library_nf_rt_native_nanoFramework_Runtime_Native_SystemInfo::get_OEMString___STATIC__STRING,
    Library_nf_rt_native_nanoFramework_Runtime_Native_SystemInfo::get_OEM___STATIC__U1,
    Library_nf_rt_native_nanoFramework_Runtime_Native_SystemInfo::get_Model___STATIC__U1,
    Library_nf_rt_native_nanoFramework_Runtime_Native_SystemInfo::get_SKU___STATIC__U2,
    NULL,
    Library_nf_rt_native_nanoFramework_Runtime_Native_SystemInfo::GetNativeFloatingPointSupport___STATIC__U1,
    NULL,
    Library_nf_rt_native_nanoFramework_Runtime_Native_Debug::GC___STATIC__U4__BOOLEAN,
    Library_nf_rt_native_nanoFramework_Runtime_Native_Debug::EnableGCMessages___STATIC__VOID__BOOLEAN,
    NULL,
    NULL,
    NULL,
    Library_nf_rt_native_nanoFramework_Runtime_Native_ExecutionConstraint::Install___STATIC__VOID__I4__I4,
    NULL,
    NULL,
    NULL,
    NULL,
    NULL,
    Library_nf_rt_native_nanoFramework_Runtime_Native_Power::NativeReboot___STATIC__VOID,
    NULL,
    NULL,
    NULL,
    NULL,
    NULL,
    Library_nf_rt_native_nanoFramework_Runtime_Native_ResourceUtility::GetObject___STATIC__OBJECT__mscorlibSystemResourcesResourceManager__mscorlibSystemEnum,
    Library_nf_rt_native_nanoFramework_Runtime_Native_ResourceUtility::GetObject___STATIC__OBJECT__mscorlibSystemResourcesResourceManager__mscorlibSystemEnum__I4__I4,
    NULL,
    NULL,
    NULL,
    Library_nf_rt_native_nanoFramework_Runtime_Native_Rtc::Native_RTC_SetSystemTime___STATIC__BOOLEAN__I4__U1__U1__U1__U1__U1__U1,
};

const CLR_RT_NativeAssemblyData g_CLR_AssemblyNative_nanoFramework_Runtime_Native =
{
    "nanoFramework.Runtime.Native",
    0x63411111,
    method_lookup,
    { 1, 0, 2, 4 }
};
<commit_msg>Update nanoFramework.Runtime.Native version to 1.0.2-preview-009 ***NO_CI*** (#993)<commit_after>//
// Copyright (c) 2017 The nanoFramework project contributors
// Portions Copyright (c) Microsoft Corporation.  All rights reserved.
// See LICENSE file in the project root for full license information.
//

#include "nf_rt_native.h"

static const CLR_RT_MethodHandler method_lookup[] =
{
    Library_nf_rt_native_nanoFramework_Runtime_Native_SystemInfo::GetSystemVersion___STATIC__VOID__BYREF_I4__BYREF_I4__BYREF_I4__BYREF_I4,
    NULL,
    Library_nf_rt_native_nanoFramework_Runtime_Native_SystemInfo::get_OEMString___STATIC__STRING,
    Library_nf_rt_native_nanoFramework_Runtime_Native_SystemInfo::get_OEM___STATIC__U1,
    Library_nf_rt_native_nanoFramework_Runtime_Native_SystemInfo::get_Model___STATIC__U1,
    Library_nf_rt_native_nanoFramework_Runtime_Native_SystemInfo::get_SKU___STATIC__U2,
    NULL,
    Library_nf_rt_native_nanoFramework_Runtime_Native_SystemInfo::GetNativeFloatingPointSupport___STATIC__U1,
    NULL,
    Library_nf_rt_native_nanoFramework_Runtime_Native_Debug::GC___STATIC__U4__BOOLEAN,
    Library_nf_rt_native_nanoFramework_Runtime_Native_Debug::EnableGCMessages___STATIC__VOID__BOOLEAN,
    NULL,
    NULL,
    NULL,
    Library_nf_rt_native_nanoFramework_Runtime_Native_ExecutionConstraint::Install___STATIC__VOID__I4__I4,
    NULL,
    NULL,
    NULL,
    NULL,
    NULL,
    Library_nf_rt_native_nanoFramework_Runtime_Native_Power::NativeReboot___STATIC__VOID,
    NULL,
    NULL,
    NULL,
    NULL,
    NULL,
    Library_nf_rt_native_nanoFramework_Runtime_Native_ResourceUtility::GetObject___STATIC__OBJECT__mscorlibSystemResourcesResourceManager__mscorlibSystemEnum,
    Library_nf_rt_native_nanoFramework_Runtime_Native_ResourceUtility::GetObject___STATIC__OBJECT__mscorlibSystemResourcesResourceManager__mscorlibSystemEnum__I4__I4,
    NULL,
    NULL,
    NULL,
    Library_nf_rt_native_nanoFramework_Runtime_Native_Rtc::Native_RTC_SetSystemTime___STATIC__BOOLEAN__I4__U1__U1__U1__U1__U1__U1,
};

const CLR_RT_NativeAssemblyData g_CLR_AssemblyNative_nanoFramework_Runtime_Native =
{
    "nanoFramework.Runtime.Native",
    0x63411111,
    method_lookup,
    { 1, 0, 2, 9 }
};
<|endoftext|>


<commit_before>#include <Bindings/Bindings.hpp>
#include <Bindings/TransformBindings.hpp>
#include <Transform/Polygon.hpp>
#include <Transform/ProtectedUnitVector.hpp>
#include <Transform/Rect.hpp>
#include <Transform/UnitBasedObject.hpp>
#include <Transform/UnitVector.hpp>

#include <kaguya/kaguya.hpp>

namespace obe::Bindings::TransformBindings
{
    void LoadMovable(kaguya::State* lua)
    {
        Load(lua, "obe.Identifiable");
        (*lua)["obe"]["Movable"].setClass(
            kaguya::UserdataMetatable<Transform::Movable>()
                .addFunction("getPosition", &Transform::Movable::getPosition)
                .addFunction("move", &Transform::Movable::move)
                .addFunction("setPosition", &Transform::Movable::setPosition));
    }

    void LoadProtectedUnitVector(kaguya::State* lua)
    {
        Load(lua, "obe.UnitVector");
        (*lua)["obe"]["ProtectedUnitVector"].setClass(
            kaguya::UserdataMetatable<Transform::ProtectedUnitVector,
                                      Transform::UnitVector>());
    }

    KAGUYA_MEMBER_FUNCTION_OVERLOADS_WITH_SIGNATURE(
        Rect_getPosition_wrapper, Transform::Rect, getPosition, 0, 1,
        Transform::UnitVector (Transform::Rect::*)(Transform::Referential));
    KAGUYA_MEMBER_FUNCTION_OVERLOADS_WITH_SIGNATURE(
        Rect_movePoint_wrapper, Transform::Rect, movePoint, 1, 2,
        void (Transform::Rect::*)(const Transform::UnitVector&,
                                  Transform::Referential));
    KAGUYA_MEMBER_FUNCTION_OVERLOADS_WITH_SIGNATURE(
        Rect_scale_wrapper, Transform::Rect, scale, 1, 2,
        void (Transform::Rect::*)(const Transform::UnitVector&,
                                  Transform::Referential));
    KAGUYA_MEMBER_FUNCTION_OVERLOADS_WITH_SIGNATURE(
        Rect_setPointPosition_wrapper, Transform::Rect, setPointPosition, 1, 2,
        void (Transform::Rect::*)(const Transform::UnitVector&,
                                  Transform::Referential));
    KAGUYA_MEMBER_FUNCTION_OVERLOADS_WITH_SIGNATURE(
        Rect_setPosition_wrapper, Transform::Rect, setPosition, 1, 2,
        void (Transform::Rect::*)(const Transform::UnitVector&,
                                  Transform::Referential));
    KAGUYA_MEMBER_FUNCTION_OVERLOADS_WITH_SIGNATURE(
        Rect_setSize_wrapper, Transform::Rect, setSize, 1, 2,
        void (Transform::Rect::*)(const Transform::UnitVector&,
                                  Transform::Referential));
    void LoadRect(kaguya::State* lua)
    {
        Load(lua, "obe.Movable");
        (*lua)["obe"]["Rect"].setClass(
            kaguya::UserdataMetatable<Transform::Rect, Transform::Movable>()
                .setConstructors<Transform::Rect(),
                                 Transform::Rect(
                                     const Transform::UnitVector&,
                                     const Transform::UnitVector&)>()
                .addFunction("getPosition", Rect_getPosition_wrapper())
                .addFunction("getScaleFactor", &Transform::Rect::getScaleFactor)
                .addFunction("getSize", &Transform::Rect::getSize)
                .addFunction("move", &Transform::Rect::move)
                .addFunction("movePoint", Rect_movePoint_wrapper())
                .addFunction("rotate", &Transform::Rect::rotate)
                .addFunction("scale", Rect_scale_wrapper())
                .addFunction("setPointPosition",
                             Rect_setPointPosition_wrapper())
                .addFunction("setPosition", Rect_setPosition_wrapper())
                .addFunction("setRotation", &Transform::Rect::setRotation)
                .addFunction("setSize", Rect_setSize_wrapper())
                .addFunction("transformRef", &Transform::Rect::transformRef));
    }

    void LoadReferential(kaguya::State* lua)
    {
        (*lua)["obe"]["Referential"] = kaguya::NewTable();
        (*lua)["obe"]["Referential"]["Bottom"] = Transform::Referential::Bottom;
        (*lua)["obe"]["Referential"]["BottomLeft"] =
            Transform::Referential::BottomLeft;
        (*lua)["obe"]["Referential"]["BottomRight"] =
            Transform::Referential::BottomRight;
        (*lua)["obe"]["Referential"]["Center"] = Transform::Referential::Center;
        (*lua)["obe"]["Referential"]["Left"] = Transform::Referential::Left;
        (*lua)["obe"]["Referential"]["Right"] = Transform::Referential::Right;
        (*lua)["obe"]["Referential"]["Top"] = Transform::Referential::Top;
        (*lua)["obe"]["Referential"]["TopLeft"] =
            Transform::Referential::TopLeft;
        (*lua)["obe"]["Referential"]["TopRight"] =
            Transform::Referential::TopRight;
    }

    void LoadUnitBasedObject(kaguya::State* lua)
    {
        (*lua)["obe"]["UnitBasedObject"].setClass(
            kaguya::UserdataMetatable<Transform::UnitBasedObject>()
                .addFunction("getWorkingUnit",
                             &Transform::UnitBasedObject::getWorkingUnit)
                .addFunction("setWorkingUnit",
                             &Transform::UnitBasedObject::setWorkingUnit));
    }
    void LoadUnitVector(kaguya::State* lua)
    {
        (*lua)["obe"]["UnitVector"].setClass(
            kaguya::UserdataMetatable<Transform::UnitVector>()
                .setConstructors<Transform::UnitVector(),
                                 Transform::UnitVector(Transform::Units),
                                 Transform::UnitVector(double, double),
                                 Transform::UnitVector(double, double,
                                                       Transform::Units)>()
                .addOverloadedFunctions(
                    "add",
                    static_cast<void (Transform::UnitVector::*)(
                        const Transform::UnitVector&)>(
                        &Transform::UnitVector::add),
                    static_cast<void (Transform::UnitVector::*)(
                        double, double)>(&Transform::UnitVector::add))
                .addOverloadedFunctions(
                    "__add",
                    static_cast<Transform::UnitVector (
                        Transform::UnitVector::*)(const Transform::UnitVector&)
                                    const>(&Transform::UnitVector::operator+),
                    static_cast<Transform::UnitVector (
                        Transform::UnitVector::*)(double) const>(
                        &Transform::UnitVector::operator+))
                .addOverloadedFunctions(
                    "__sub",
                    static_cast<Transform::UnitVector (
                        Transform::UnitVector::*)(const Transform::UnitVector&)
                                    const>(&Transform::UnitVector::operator-),
                    static_cast<Transform::UnitVector (
                        Transform::UnitVector::*)(double) const>(
                        &Transform::UnitVector::operator-))
                .addOverloadedFunctions(
                    "__mul",
                    static_cast<Transform::UnitVector (
                        Transform::UnitVector::*)(const Transform::UnitVector&)
                                    const>(&Transform::UnitVector::operator*),
                    static_cast<Transform::UnitVector (
                        Transform::UnitVector::*)(double) const>(
                        &Transform::UnitVector::operator*))
                .addOverloadedFunctions(
                    "__div",
                    static_cast<Transform::UnitVector (
                        Transform::UnitVector::*)(const Transform::UnitVector&)
                                    const>(&Transform::UnitVector::operator/),
                    static_cast<Transform::UnitVector (
                        Transform::UnitVector::*)(double) const>(
                        &Transform::UnitVector::operator/))
                .addOverloadedFunctions(
                    "set",
                    static_cast<void (Transform::UnitVector::*)(
                        const Transform::UnitVector&)>(
                        &Transform::UnitVector::set),
                    static_cast<void (Transform::UnitVector::*)(
                        double, double)>(&Transform::UnitVector::set))
                .addFunction("__eq", &Transform::UnitVector::operator==)
                .addFunction(
                    "to",
                    static_cast<Transform::UnitVector (
                        Transform::UnitVector::*)(Transform::Units) const>(
                        &Transform::UnitVector::to))
                .addProperty("x", &Transform::UnitVector::x)
                .addProperty("y", &Transform::UnitVector::y)
                .addProperty("unit", &Transform::UnitVector::unit));
    }

    Transform::PolygonSegment* Polygon_getSegmentContainingPoint_subwrapper(
        Transform::Polygon& polygon, const Transform::UnitVector& position,
        double tolerance = Transform::Polygon::DefaultTolerance)
    {
        auto optret = polygon.getSegmentContainingPoint(position, tolerance);
        if (optret.has_value())
        {
            return &optret.value();
        }
        else
        {
            Transform::PolygonSegment* nullsegment = nullptr;
            return nullsegment;
        }
    }
    KAGUYA_FUNCTION_OVERLOADS(Polygon_getSegmentContainingPoint_wrapper,
                              Polygon_getSegmentContainingPoint_subwrapper, 2,
                              3)
    KAGUYA_MEMBER_FUNCTION_OVERLOADS(Polygon_addPoint_wrapper,
                                     Transform::Polygon, addPoint, 1, 2);
    KAGUYA_MEMBER_FUNCTION_OVERLOADS(Polygon_findClosestPoint_wrapper,
                                     Transform::Polygon, findClosestPoint, 1,
                                     3);
    void LoadPolygon(kaguya::State* lua)
    {
        Load(lua, "obe.Movable");
        Load(lua, "obe.UnitBasedObject");
        Load(lua, "obe.UnitVector");
        (*lua)["obe"]["PolygonPoint"].setClass(
            kaguya::UserdataMetatable<Transform::PolygonPoint,
                                      Transform::UnitVector>()
                .addFunction("distance", &Transform::PolygonPoint::distance)
                .addFunction("getRelativePosition",
                             &Transform::PolygonPoint::getRelativePosition)
                .addFunction("move", &Transform::PolygonPoint::move)
                .addFunction("remove", &Transform::PolygonPoint::remove)
                .addFunction("setRelativePosition",
                             &Transform::PolygonPoint::setRelativePosition));
        (*lua)["obe"]["PolygonPoint"]["RelativePositionFrom"] =
            kaguya::NewTable();
        (*lua)["obe"]["PolygonPoint"]["RelativePositionFrom"]["Point0"] =
            Transform::PolygonPoint::RelativePositionFrom::Point0;
        (*lua)["obe"]["PolygonPoint"]["RelativePositionFrom"]["Centroid"] =
            Transform::PolygonPoint::RelativePositionFrom::Centroid;
        (*lua)["obe"]["PolygonPoint"]["index"] = kaguya::function(
            [](Transform::PolygonPoint& point) { return point.index; });
        (*lua)["obe"]["PolygonSegment"].setClass(
            kaguya::UserdataMetatable<Transform::PolygonSegment>()
                .setConstructors<Transform::PolygonSegment(
                    const Transform::PolygonPoint&,
                    const Transform::PolygonPoint&)>()
                .addFunction("getAngle", &Transform::PolygonSegment::getAngle)
                .addFunction("getLength",
                             &Transform::PolygonSegment::getLength));
        (*lua)["obe"]["PolygonSegment"]["first"] = kaguya::function(
            [](Transform::PolygonSegment& segment) { return &segment.first; });
        (*lua)["obe"]["PolygonSegment"]["second"] = kaguya::function(
            [](Transform::PolygonSegment& segment) { return &segment.second; });
        (*lua)["obe"]["Polygon"].setClass(
            kaguya::UserdataMetatable<
                Transform::Polygon,
                kaguya::MultipleBase<Transform::UnitBasedObject,
                                     Transform::Movable>>()
                .addFunction("addPoint", Polygon_addPoint_wrapper())
                .addFunction("findClosestSegment",
                             &Transform::Polygon::findClosestSegment)
                .addFunction("findClosestPoint",
                             Polygon_findClosestPoint_wrapper())
                .addFunction("getBoundingBox",
                             &Transform::Polygon::getBoundingBox)
                .addFunction("getCentroid", &Transform::Polygon::getCentroid)
                .addFunction("getPointsAmount",
                             &Transform::Polygon::getPointsAmount)
                .addFunction("getPosition", &Transform::Polygon::getPosition)
                .addFunction("getRotation", &Transform::Polygon::getRotation)
                .addFunction("getSegment", &Transform::Polygon::getSegment)
                .addFunction("isCentroidAroundPosition",
                             &Transform::Polygon::isCentroidAroundPosition)
                .addFunction("move", &Transform::Polygon::move)
                .addFunction("rotate", &Transform::Polygon::rotate)
                .addFunction("setPosition", &Transform::Polygon::setPosition)
                .addFunction("setPositionFromCentroid",
                             &Transform::Polygon::setPositionFromCentroid)
                .addFunction("setRotation", &Transform::Polygon::setRotation));
        (*lua)["obe"]["Polygon"]["get"] = kaguya::function(
            [](Transform::Polygon& polygon, Transform::point_index_t index) {
                return &polygon.get(index);
            });
        (*lua)["obe"]["Polygon"]["getAllPoints"] =
            kaguya::function([](Transform::Polygon& polygon) {
                std::vector<Transform::PolygonPoint*> points;
                for (const auto& point : polygon.getAllPoints())
                    points.push_back(point.get());
                return points;
            });
        (*lua)["obe"]["Polygon"]["getPointAroundPosition"] =
            kaguya::function([](Transform::Polygon& polygon,
                                const Transform::UnitVector& position,
                                const Transform::UnitVector& tolerance) {
                auto optret =
                    polygon.getPointAroundPosition(position, tolerance);
                if (optret.has_value())
                {
                    return optret.value();
                }
                else
                {
                    Transform::PolygonPoint* nullpoint = nullptr;
                    return nullpoint;
                }
            });
        (*lua)["obe"]["Polygon"]["getSegmentContainingPoint"] =
            kaguya::function(Polygon_getSegmentContainingPoint_wrapper());
    }

    void LoadUnits(kaguya::State* lua)
    {
        (*lua)["obe"]["Units"] = kaguya::NewTable();
        (*lua)["obe"]["Units"]["ViewPercentage"] =
            Transform::Units::ViewPercentage;
        (*lua)["obe"]["Units"]["ViewPixels"] = Transform::Units::ViewPixels;
        (*lua)["obe"]["Units"]["ViewUnits"] = Transform::Units::ViewUnits;
        (*lua)["obe"]["Units"]["ScenePixels"] = Transform::Units::ScenePixels;
        (*lua)["obe"]["Units"]["SceneUnits"] = Transform::Units::SceneUnits;
    }
} // namespace obe::Bindings::TransformBindings<commit_msg>Added missing getRotation binding<commit_after>#include <Bindings/Bindings.hpp>
#include <Bindings/TransformBindings.hpp>
#include <Transform/Polygon.hpp>
#include <Transform/ProtectedUnitVector.hpp>
#include <Transform/Rect.hpp>
#include <Transform/UnitBasedObject.hpp>
#include <Transform/UnitVector.hpp>

#include <kaguya/kaguya.hpp>

namespace obe::Bindings::TransformBindings
{
    void LoadMovable(kaguya::State* lua)
    {
        Load(lua, "obe.Identifiable");
        (*lua)["obe"]["Movable"].setClass(
            kaguya::UserdataMetatable<Transform::Movable>()
                .addFunction("getPosition", &Transform::Movable::getPosition)
                .addFunction("move", &Transform::Movable::move)
                .addFunction("setPosition", &Transform::Movable::setPosition));
    }

    void LoadProtectedUnitVector(kaguya::State* lua)
    {
        Load(lua, "obe.UnitVector");
        (*lua)["obe"]["ProtectedUnitVector"].setClass(
            kaguya::UserdataMetatable<Transform::ProtectedUnitVector,
                                      Transform::UnitVector>());
    }

    KAGUYA_MEMBER_FUNCTION_OVERLOADS_WITH_SIGNATURE(
        Rect_getPosition_wrapper, Transform::Rect, getPosition, 0, 1,
        Transform::UnitVector (Transform::Rect::*)(Transform::Referential));
    KAGUYA_MEMBER_FUNCTION_OVERLOADS_WITH_SIGNATURE(
        Rect_movePoint_wrapper, Transform::Rect, movePoint, 1, 2,
        void (Transform::Rect::*)(const Transform::UnitVector&,
                                  Transform::Referential));
    KAGUYA_MEMBER_FUNCTION_OVERLOADS_WITH_SIGNATURE(
        Rect_scale_wrapper, Transform::Rect, scale, 1, 2,
        void (Transform::Rect::*)(const Transform::UnitVector&,
                                  Transform::Referential));
    KAGUYA_MEMBER_FUNCTION_OVERLOADS_WITH_SIGNATURE(
        Rect_setPointPosition_wrapper, Transform::Rect, setPointPosition, 1, 2,
        void (Transform::Rect::*)(const Transform::UnitVector&,
                                  Transform::Referential));
    KAGUYA_MEMBER_FUNCTION_OVERLOADS_WITH_SIGNATURE(
        Rect_setPosition_wrapper, Transform::Rect, setPosition, 1, 2,
        void (Transform::Rect::*)(const Transform::UnitVector&,
                                  Transform::Referential));
    KAGUYA_MEMBER_FUNCTION_OVERLOADS_WITH_SIGNATURE(
        Rect_setSize_wrapper, Transform::Rect, setSize, 1, 2,
        void (Transform::Rect::*)(const Transform::UnitVector&,
                                  Transform::Referential));
    void LoadRect(kaguya::State* lua)
    {
        Load(lua, "obe.Movable");
        (*lua)["obe"]["Rect"].setClass(
            kaguya::UserdataMetatable<Transform::Rect, Transform::Movable>()
                .setConstructors<Transform::Rect(),
                                 Transform::Rect(
                                     const Transform::UnitVector&,
                                     const Transform::UnitVector&)>()
                .addFunction("getPosition", Rect_getPosition_wrapper())
                .addFunction("getRotation", &Transform::Rect::getRotation)
                .addFunction("getScaleFactor", &Transform::Rect::getScaleFactor)
                .addFunction("getSize", &Transform::Rect::getSize)
                .addFunction("move", &Transform::Rect::move)
                .addFunction("movePoint", Rect_movePoint_wrapper())
                .addFunction("rotate", &Transform::Rect::rotate)
                .addFunction("scale", Rect_scale_wrapper())
                .addFunction("setPointPosition",
                             Rect_setPointPosition_wrapper())
                .addFunction("setPosition", Rect_setPosition_wrapper())
                .addFunction("setRotation", &Transform::Rect::setRotation)
                .addFunction("setSize", Rect_setSize_wrapper())
                .addFunction("transformRef", &Transform::Rect::transformRef));
    }

    void LoadReferential(kaguya::State* lua)
    {
        (*lua)["obe"]["Referential"] = kaguya::NewTable();
        (*lua)["obe"]["Referential"]["Bottom"] = Transform::Referential::Bottom;
        (*lua)["obe"]["Referential"]["BottomLeft"] =
            Transform::Referential::BottomLeft;
        (*lua)["obe"]["Referential"]["BottomRight"] =
            Transform::Referential::BottomRight;
        (*lua)["obe"]["Referential"]["Center"] = Transform::Referential::Center;
        (*lua)["obe"]["Referential"]["Left"] = Transform::Referential::Left;
        (*lua)["obe"]["Referential"]["Right"] = Transform::Referential::Right;
        (*lua)["obe"]["Referential"]["Top"] = Transform::Referential::Top;
        (*lua)["obe"]["Referential"]["TopLeft"] =
            Transform::Referential::TopLeft;
        (*lua)["obe"]["Referential"]["TopRight"] =
            Transform::Referential::TopRight;
    }

    void LoadUnitBasedObject(kaguya::State* lua)
    {
        (*lua)["obe"]["UnitBasedObject"].setClass(
            kaguya::UserdataMetatable<Transform::UnitBasedObject>()
                .addFunction("getWorkingUnit",
                             &Transform::UnitBasedObject::getWorkingUnit)
                .addFunction("setWorkingUnit",
                             &Transform::UnitBasedObject::setWorkingUnit));
    }
    void LoadUnitVector(kaguya::State* lua)
    {
        (*lua)["obe"]["UnitVector"].setClass(
            kaguya::UserdataMetatable<Transform::UnitVector>()
                .setConstructors<Transform::UnitVector(),
                                 Transform::UnitVector(Transform::Units),
                                 Transform::UnitVector(double, double),
                                 Transform::UnitVector(double, double,
                                                       Transform::Units)>()
                .addOverloadedFunctions(
                    "add",
                    static_cast<void (Transform::UnitVector::*)(
                        const Transform::UnitVector&)>(
                        &Transform::UnitVector::add),
                    static_cast<void (Transform::UnitVector::*)(
                        double, double)>(&Transform::UnitVector::add))
                .addOverloadedFunctions(
                    "__add",
                    static_cast<Transform::UnitVector (
                        Transform::UnitVector::*)(const Transform::UnitVector&)
                                    const>(&Transform::UnitVector::operator+),
                    static_cast<Transform::UnitVector (
                        Transform::UnitVector::*)(double) const>(
                        &Transform::UnitVector::operator+))
                .addOverloadedFunctions(
                    "__sub",
                    static_cast<Transform::UnitVector (
                        Transform::UnitVector::*)(const Transform::UnitVector&)
                                    const>(&Transform::UnitVector::operator-),
                    static_cast<Transform::UnitVector (
                        Transform::UnitVector::*)(double) const>(
                        &Transform::UnitVector::operator-))
                .addOverloadedFunctions(
                    "__mul",
                    static_cast<Transform::UnitVector (
                        Transform::UnitVector::*)(const Transform::UnitVector&)
                                    const>(&Transform::UnitVector::operator*),
                    static_cast<Transform::UnitVector (
                        Transform::UnitVector::*)(double) const>(
                        &Transform::UnitVector::operator*))
                .addOverloadedFunctions(
                    "__div",
                    static_cast<Transform::UnitVector (
                        Transform::UnitVector::*)(const Transform::UnitVector&)
                                    const>(&Transform::UnitVector::operator/),
                    static_cast<Transform::UnitVector (
                        Transform::UnitVector::*)(double) const>(
                        &Transform::UnitVector::operator/))
                .addOverloadedFunctions(
                    "set",
                    static_cast<void (Transform::UnitVector::*)(
                        const Transform::UnitVector&)>(
                        &Transform::UnitVector::set),
                    static_cast<void (Transform::UnitVector::*)(
                        double, double)>(&Transform::UnitVector::set))
                .addFunction("__eq", &Transform::UnitVector::operator==)
                .addFunction(
                    "to",
                    static_cast<Transform::UnitVector (
                        Transform::UnitVector::*)(Transform::Units) const>(
                        &Transform::UnitVector::to))
                .addProperty("x", &Transform::UnitVector::x)
                .addProperty("y", &Transform::UnitVector::y)
                .addProperty("unit", &Transform::UnitVector::unit));
    }

    Transform::PolygonSegment* Polygon_getSegmentContainingPoint_subwrapper(
        Transform::Polygon& polygon, const Transform::UnitVector& position,
        double tolerance = Transform::Polygon::DefaultTolerance)
    {
        auto optret = polygon.getSegmentContainingPoint(position, tolerance);
        if (optret.has_value())
        {
            return &optret.value();
        }
        else
        {
            Transform::PolygonSegment* nullsegment = nullptr;
            return nullsegment;
        }
    }
    KAGUYA_FUNCTION_OVERLOADS(Polygon_getSegmentContainingPoint_wrapper,
                              Polygon_getSegmentContainingPoint_subwrapper, 2,
                              3)
    KAGUYA_MEMBER_FUNCTION_OVERLOADS(Polygon_addPoint_wrapper,
                                     Transform::Polygon, addPoint, 1, 2);
    KAGUYA_MEMBER_FUNCTION_OVERLOADS(Polygon_findClosestPoint_wrapper,
                                     Transform::Polygon, findClosestPoint, 1,
                                     3);
    void LoadPolygon(kaguya::State* lua)
    {
        Load(lua, "obe.Movable");
        Load(lua, "obe.UnitBasedObject");
        Load(lua, "obe.UnitVector");
        (*lua)["obe"]["PolygonPoint"].setClass(
            kaguya::UserdataMetatable<Transform::PolygonPoint,
                                      Transform::UnitVector>()
                .addFunction("distance", &Transform::PolygonPoint::distance)
                .addFunction("getRelativePosition",
                             &Transform::PolygonPoint::getRelativePosition)
                .addFunction("move", &Transform::PolygonPoint::move)
                .addFunction("remove", &Transform::PolygonPoint::remove)
                .addFunction("setRelativePosition",
                             &Transform::PolygonPoint::setRelativePosition));
        (*lua)["obe"]["PolygonPoint"]["RelativePositionFrom"] =
            kaguya::NewTable();
        (*lua)["obe"]["PolygonPoint"]["RelativePositionFrom"]["Point0"] =
            Transform::PolygonPoint::RelativePositionFrom::Point0;
        (*lua)["obe"]["PolygonPoint"]["RelativePositionFrom"]["Centroid"] =
            Transform::PolygonPoint::RelativePositionFrom::Centroid;
        (*lua)["obe"]["PolygonPoint"]["index"] = kaguya::function(
            [](Transform::PolygonPoint& point) { return point.index; });
        (*lua)["obe"]["PolygonSegment"].setClass(
            kaguya::UserdataMetatable<Transform::PolygonSegment>()
                .setConstructors<Transform::PolygonSegment(
                    const Transform::PolygonPoint&,
                    const Transform::PolygonPoint&)>()
                .addFunction("getAngle", &Transform::PolygonSegment::getAngle)
                .addFunction("getLength",
                             &Transform::PolygonSegment::getLength));
        (*lua)["obe"]["PolygonSegment"]["first"] = kaguya::function(
            [](Transform::PolygonSegment& segment) { return &segment.first; });
        (*lua)["obe"]["PolygonSegment"]["second"] = kaguya::function(
            [](Transform::PolygonSegment& segment) { return &segment.second; });
        (*lua)["obe"]["Polygon"].setClass(
            kaguya::UserdataMetatable<
                Transform::Polygon,
                kaguya::MultipleBase<Transform::UnitBasedObject,
                                     Transform::Movable>>()
                .addFunction("addPoint", Polygon_addPoint_wrapper())
                .addFunction("findClosestSegment",
                             &Transform::Polygon::findClosestSegment)
                .addFunction("findClosestPoint",
                             Polygon_findClosestPoint_wrapper())
                .addFunction("getBoundingBox",
                             &Transform::Polygon::getBoundingBox)
                .addFunction("getCentroid", &Transform::Polygon::getCentroid)
                .addFunction("getPointsAmount",
                             &Transform::Polygon::getPointsAmount)
                .addFunction("getPosition", &Transform::Polygon::getPosition)
                .addFunction("getRotation", &Transform::Polygon::getRotation)
                .addFunction("getSegment", &Transform::Polygon::getSegment)
                .addFunction("isCentroidAroundPosition",
                             &Transform::Polygon::isCentroidAroundPosition)
                .addFunction("move", &Transform::Polygon::move)
                .addFunction("rotate", &Transform::Polygon::rotate)
                .addFunction("setPosition", &Transform::Polygon::setPosition)
                .addFunction("setPositionFromCentroid",
                             &Transform::Polygon::setPositionFromCentroid)
                .addFunction("setRotation", &Transform::Polygon::setRotation));
        (*lua)["obe"]["Polygon"]["get"] = kaguya::function(
            [](Transform::Polygon& polygon, Transform::point_index_t index) {
                return &polygon.get(index);
            });
        (*lua)["obe"]["Polygon"]["getAllPoints"] =
            kaguya::function([](Transform::Polygon& polygon) {
                std::vector<Transform::PolygonPoint*> points;
                for (const auto& point : polygon.getAllPoints())
                    points.push_back(point.get());
                return points;
            });
        (*lua)["obe"]["Polygon"]["getPointAroundPosition"] =
            kaguya::function([](Transform::Polygon& polygon,
                                const Transform::UnitVector& position,
                                const Transform::UnitVector& tolerance) {
                auto optret =
                    polygon.getPointAroundPosition(position, tolerance);
                if (optret.has_value())
                {
                    return optret.value();
                }
                else
                {
                    Transform::PolygonPoint* nullpoint = nullptr;
                    return nullpoint;
                }
            });
        (*lua)["obe"]["Polygon"]["getSegmentContainingPoint"] =
            kaguya::function(Polygon_getSegmentContainingPoint_wrapper());
    }

    void LoadUnits(kaguya::State* lua)
    {
        (*lua)["obe"]["Units"] = kaguya::NewTable();
        (*lua)["obe"]["Units"]["ViewPercentage"] =
            Transform::Units::ViewPercentage;
        (*lua)["obe"]["Units"]["ViewPixels"] = Transform::Units::ViewPixels;
        (*lua)["obe"]["Units"]["ViewUnits"] = Transform::Units::ViewUnits;
        (*lua)["obe"]["Units"]["ScenePixels"] = Transform::Units::ScenePixels;
        (*lua)["obe"]["Units"]["SceneUnits"] = Transform::Units::SceneUnits;
    }
} // namespace obe::Bindings::TransformBindings<|endoftext|>


<commit_before>/*
  For more information, please see: http://software.sci.utah.edu

  The MIT License

  Copyright (c) 2009 Scientific Computing and Imaging Institute,
  University of Utah.

  Permission is hereby granted, free of charge, to any person obtaining a
  copy of this software and associated documentation files (the "Software"),
  to deal in the Software without restriction, including without limitation
  the rights to use, copy, modify, merge, publish, distribute, sublicense,
  and/or sell copies of the Software, and to permit persons to whom the
  Software is furnished to do so, subject to the following conditions:

  The above copyright notice and this permission notice shall be included
  in all copies or substantial portions of the Software.

  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
  OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
  THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
  FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
  DEALINGS IN THE SOFTWARE.
*/

#include <Core/IEPlugin/MatlabFiles_Plugin.h>
#include <Core/Matlab/matlabfile.h>
#include <Core/Matlab/matlabarray.h>
#include <Core/Matlab/matlabconverter.h>
#include <Core/Datatypes/Matrix.h>
#include <Core/Datatypes/Legacy/Field/Field.h>
#include <Core/Datatypes/Legacy/Nrrd/NrrdData.h>
#include <Core/Datatypes/Legacy/Base/PropertyManager.h>

// This file contains plugins to read and write files in MathWork's Matlab
// file format.

using namespace SCIRun;
using namespace SCIRun::MatlabIO;
using namespace SCIRun::Core::Logging;
using namespace SCIRun::Core::Datatypes;

// Write a matrix as matlab object
MatrixHandle
SCIRun::MatlabMatrix_reader(LoggerHandle pr, const char *filename)
{
  // Create a matlab file object, which will be linked to input file
  matlabfile mf;
  // Instantiate the matlab converter between SCIRun objects and Matlab objects
  matlabconverter mc(pr);
  // Define a matlab array for in the matlab file
  matlabarray ma;

  // The engine will generate an information string which we will ignore
  std::string dummytext;

  // Define the output handle
  MatrixHandle mh = 0;

  try
  {
    // Open the file
    mf.open(std::string(filename),"r");
    // Get the number of matlab objects in the file
    int numarrays = mf.getnummatlabarrays();
    // Find the first one that is suitable
    for (int p=0;p<numarrays;p++)
    {
      // Extract only the object's header
      ma = mf.getmatlabarrayinfo(p);
      // Check whether we could convert it into a matrix object
      if (mc.sciMatrixCompatible(ma,dummytext))
      {
        // Read the full object
        ma = mf.getmatlabarray(p);
        // Convert the object into a SCIRun object
        mc.mlArrayTOsciMatrix(ma,mh); break;
      }
    }
    mf.close();
  }
  catch (...)
  {
    mh = 0;
  }

  return(mh);
}

bool
SCIRun::MatlabMatrix_writer(LoggerHandle pr,
			   MatrixHandle mh, const char *filename)
{
  matlabfile mf;
  matlabconverter mc(pr);
  matlabarray ma;
  std::string name;

  try
  {
    // Make sure we convert it to a numeric matrix, remove all annotation
    // This is the most common case
    mc.converttonumericmatrix();
    // Convert the matrix into a matlab object
    mc.sciMatrixTOmlArray(mh,ma);
    // If the SCIRun object has a name, use it
    mh->properties().get_property("name",name);
    // Set a default name if none was supplied
    if ((name=="")||(!mc.isvalidmatrixname(name))) name = "scirunmatrix";
    // Open the file
    mf.open(std::string(filename),"w");
    // Write the file
    mf.putmatlabarray(ma,name);
    // Close the file
    mf.close();
  }
  catch (...)
  {
    return(false);
  }
  return(true);
}

NrrdDataHandle
SCIRun::MatlabNrrd_reader(LoggerHandle pr, const char *filename)
{
  matlabfile mf;
  matlabconverter mc(pr);
  matlabarray ma;
  std::string dummytext;
  NrrdDataHandle mh;

  mh = 0;

  try
  {
    // Open the matlab file
    mf.open(std::string(filename),"r");
    // Check how many matlab objects are in the file
    int numarrays = mf.getnummatlabarrays();
    // Find the first one we can convert
    for (int p=0;p<numarrays;p++)
    {
      // Get the header of the object only
      ma = mf.getmatlabarrayinfo(p);
      // If it is compatible with a SCIRun nrrd, get it
      if (mc.sciNrrdDataCompatible(ma,dummytext))
      {
        // Read the full object from disk
        ma = mf.getmatlabarray(p);
        // Convert the full object
        mc.mlArrayTOsciNrrdData(ma,mh); break;
      }
    }
    mf.close();
  }
  catch (...)
  {
    // If something went wrong
    mh = 0;
  }

  return(mh);
}

bool
SCIRun::MatlabNrrd_writer(LoggerHandle pr,
			   NrrdDataHandle nrrd, const char *filename)
{
  matlabfile mf;
  matlabconverter mc(pr);
  matlabarray ma;
  std::string name;

  try
  {
    // Make sure we make it into a numeric array, no annotation and headers
    mc.converttonumericmatrix();
    // Convert the object
    mc.sciNrrdDataTOmlArray(nrrd,ma);
    // Check if the object has a name
    nrrd->properties().get_property("name",name);
    // if no name available give it one
    if ((name=="")||(!mc.isvalidmatrixname(name))) name = "scirunnrrd";
    // Open the file
    mf.open(std::string(filename),"w");
    // Write the object to file
    mf.putmatlabarray(ma,name);
    // Close the file
    mf.close();
  }
  catch (...)
  {
    // in case we crashed somehow
    return(false);
  }
  return(true);
}

FieldHandle
SCIRun::MatlabField_reader(LoggerHandle pr, const char *filename)
{
  matlabfile mf;
  // Make sure that errors are forwarded in the conversion process
  matlabconverter mc(pr);
  matlabarray ma;
  std::string dummytext;
  FieldHandle mh;

  mh = 0;

  try
  {
    // Open the file
    mf.open(std::string(filename),"r");
    // How many object do we have in the file
    int numarrays = mf.getnummatlabarrays();
    // Check the objects and find the first one that is compatible with the
    // Field object
    for (int p=0;p<numarrays;p++)
    {
      // Get the header of the object
      ma = mf.getmatlabarrayinfo(p);
      // Is this object compatible?
      if (mc.sciFieldCompatible(ma,dummytext))
      {
        // If so get the full object
        ma = mf.getmatlabarray(p);
        // Convert the object to SCIRun
        mc.mlArrayTOsciField(ma,mh); break;
      }
    }
    // Close file
    mf.close();
  }
  catch (...)
  {
    // Something went wrong...
    mh = 0;
  }

  return(mh);
}

bool
SCIRun::MatlabField_writer(LoggerHandle pr,
			   FieldHandle field, const char *filename)
{
  matlabfile mf;
  // Make sure that errors are forwarded in the conversion process
  matlabconverter mc(pr);
  matlabarray ma;
  std::string name;

  try
  {
    // We want all the annotation. A field without annotation is hard to use
    mc.converttostructmatrix();
    // Convert the object
    mc.sciFieldTOmlArray(field,ma);
    // Get the name
    field->properties().get_property("name",name);
    // If no name, set a default
    if ((name=="")||(!mc.isvalidmatrixname(name))) name = "scirunfield";
    // Write the object to the file
    mf.open(std::string(filename),"w");
    mf.putmatlabarray(ma,name);
    mf.close();
  }
  catch (...)
  {
    // there is no way to signal an error to a module upstream
    return(false);
  }
  return(true);
}

<commit_msg>Small change<commit_after>/*
  For more information, please see: http://software.sci.utah.edu

  The MIT License

  Copyright (c) 2009 Scientific Computing and Imaging Institute,
  University of Utah.

  Permission is hereby granted, free of charge, to any person obtaining a
  copy of this software and associated documentation files (the "Software"),
  to deal in the Software without restriction, including without limitation
  the rights to use, copy, modify, merge, publish, distribute, sublicense,
  and/or sell copies of the Software, and to permit persons to whom the
  Software is furnished to do so, subject to the following conditions:

  The above copyright notice and this permission notice shall be included
  in all copies or substantial portions of the Software.

  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
  OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
  THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
  FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
  DEALINGS IN THE SOFTWARE.
*/

#include <Core/IEPlugin/MatlabFiles_Plugin.h>
#include <Core/Matlab/matlabfile.h>
#include <Core/Matlab/matlabarray.h>
#include <Core/Matlab/matlabconverter.h>
#include <Core/Datatypes/Matrix.h>
#include <Core/Datatypes/Legacy/Field/Field.h>
#include <Core/Datatypes/Legacy/Nrrd/NrrdData.h>
#include <Core/Datatypes/Legacy/Base/PropertyManager.h>

// This file contains plugins to read and write files in MathWork's Matlab
// file format.

using namespace SCIRun;
using namespace SCIRun::MatlabIO;
using namespace SCIRun::Core::Logging;
using namespace SCIRun::Core::Datatypes;

// Write a matrix as matlab object
MatrixHandle
SCIRun::MatlabMatrix_reader(LoggerHandle pr, const char *filename)
{
  // Create a matlab file object, which will be linked to input file
  matlabfile mf;
  // Instantiate the matlab converter between SCIRun objects and Matlab objects
  matlabconverter mc(pr);
  // Define a matlab array for in the matlab file
  matlabarray ma;

  // The engine will generate an information string which we will ignore
  std::string dummytext;

  // Define the output handle
  MatrixHandle mh = 0;

  try
  {
    // Open the file
    mf.open(std::string(filename),"r");
    // Get the number of matlab objects in the file
    int numarrays = mf.getnummatlabarrays();
    // Find the first one that is suitable
    for (int p=0;p<numarrays;p++)
    {
      // Extract only the object's header
      ma = mf.getmatlabarrayinfo(p);
      // Check whether we could convert it into a matrix object
      if (mc.sciMatrixCompatible(ma,dummytext))
      {
        // Read the full object
        ma = mf.getmatlabarray(p);
        // Convert the object into a SCIRun object
        mc.mlArrayTOsciMatrix(ma,mh); break;
      }
    }
    mf.close();
  }
  catch (...)
  {
    mh = 0;
  }

  return(mh);
}

bool
SCIRun::MatlabMatrix_writer(LoggerHandle pr,
			   MatrixHandle mh, const char *filename)
{
  matlabfile mf;
  matlabconverter mc(pr);
  matlabarray ma;
  std::string name;

  try
  {
    // Make sure we convert it to a numeric matrix, remove all annotation
    // This is the most common case
    mc.converttonumericmatrix();
    // Convert the matrix into a matlab object
    mc.sciMatrixTOmlArray(mh,ma);
    // If the SCIRun object has a name, use it
    mh->properties().get_property("name",name);
    // Set a default name if none was supplied
    if ((name=="")||(!mc.isvalidmatrixname(name))) name = "scirunmatrix";
    // Open the file
    mf.open(std::string(filename),"w");
    // Write the file
    mf.putmatlabarray(ma,name);
    // Close the file
    mf.close();
  }
  catch (...)
  {
    return(false);
  }
  return(true);
}

NrrdDataHandle
SCIRun::MatlabNrrd_reader(LoggerHandle pr, const char *filename)
{
  matlabfile mf;
  matlabconverter mc(pr);
  matlabarray ma;
  std::string dummytext;
  NrrdDataHandle mh;

  mh = 0;

  try
  {
    // Open the matlab file
    mf.open(std::string(filename),"r");
    // Check how many matlab objects are in the file
    int numarrays = mf.getnummatlabarrays();
    // Find the first one we can convert
    for (int p=0;p<numarrays;p++)
    {
      // Get the header of the object only
      ma = mf.getmatlabarrayinfo(p);
      // If it is compatible with a SCIRun nrrd, get it
      if (mc.sciNrrdDataCompatible(ma,dummytext))
      {
        // Read the full object from disk
        ma = mf.getmatlabarray(p);
        // Convert the full object
        mc.mlArrayTOsciNrrdData(ma,mh); break;
      }
    }
    mf.close();
  }
  catch (...)
  {
    // If something went wrong
    mh = 0;
  }

  return(mh);
}

bool
SCIRun::MatlabNrrd_writer(LoggerHandle pr,
			   NrrdDataHandle nrrd, const char *filename)
{
  matlabfile mf;
  matlabconverter mc(pr);
  matlabarray ma;
  std::string name;

  try
  {
    // Make sure we make it into a numeric array, no annotation and headers
    mc.converttonumericmatrix();
    // Convert the object
    mc.sciNrrdDataTOmlArray(nrrd,ma);
    // Check if the object has a name
    nrrd->properties().get_property("name",name);
    // if no name available give it one
    if ((name=="")||(!mc.isvalidmatrixname(name))) name = "scirunnrrd";
    // Open the file
    mf.open(std::string(filename),"w");
    // Write the object to file
    mf.putmatlabarray(ma,name);
    // Close the file
    mf.close();
  }
  catch (...)
  {
    // in case we crashed somehow
    return(false);
  }
  return(true);
}

FieldHandle
SCIRun::MatlabField_reader(LoggerHandle pr, const char *filename)
{
  // Make sure that errors are forwarded in the conversion process
  matlabconverter mc(pr);
  std::string dummytext;
  FieldHandle mh;

  try
  {
    matlabfile mf;
    // Open the file
    mf.open(std::string(filename),"r");
    // How many object do we have in the file
    int numarrays = mf.getnummatlabarrays();
    // Check the objects and find the first one that is compatible with the
    // Field object
    for (int p=0;p<numarrays;p++)
    {
      // Get the header of the object
      matlabarray ma = mf.getmatlabarrayinfo(p);
      // Is this object compatible?
      if (mc.sciFieldCompatible(ma,dummytext))
      {
        // If so get the full object
        ma = mf.getmatlabarray(p);
        // Convert the object to SCIRun
        mc.mlArrayTOsciField(ma,mh); break;
      }
    }
    // Close file
    mf.close();
  }
  catch (...)
  {
    // Something went wrong...
    mh = 0;
  }

  return(mh);
}

bool
SCIRun::MatlabField_writer(LoggerHandle pr,
			   FieldHandle field, const char *filename)
{
  matlabfile mf;
  // Make sure that errors are forwarded in the conversion process
  matlabconverter mc(pr);
  matlabarray ma;
  std::string name;

  try
  {
    // We want all the annotation. A field without annotation is hard to use
    mc.converttostructmatrix();
    // Convert the object
    mc.sciFieldTOmlArray(field,ma);
    // Get the name
    field->properties().get_property("name",name);
    // If no name, set a default
    if ((name=="")||(!mc.isvalidmatrixname(name))) name = "scirunfield";
    // Write the object to the file
    mf.open(std::string(filename),"w");
    mf.putmatlabarray(ma,name);
    mf.close();
  }
  catch (...)
  {
    // there is no way to signal an error to a module upstream
    return(false);
  }
  return(true);
}

<|endoftext|>


<commit_before>
/*
 * Copyright 2011 Google Inc.
 *
 * Use of this source code is governed by a BSD-style license that can be
 * found in the LICENSE file.
 */
#include "gm.h"

namespace skiagm {

/** Create a bitmap image suitable for testing SkBitmap::scrollRect().
 *
 *  @param quarterWidth bitmap will be 4x this many pixels wide
 *  @param quarterHeight bitmap will be 4x this many pixels tall
 *  @param bitmap the bitmap data is written into this object
 */
static void make_bitmap(int quarterWidth, int quarterHeight, SkBitmap *bitmap) {
    SkPaint pRed, pWhite, pGreen, pBlue, pLine, pAlphaGray;
    pRed.setColor(0xFFFF9999);
    pWhite.setColor(0xFFFFFFFF);
    pGreen.setColor(0xFF99FF99);
    pBlue.setColor(0xFF9999FF);
    pLine.setColor(0xFF000000);
    pLine.setStyle(SkPaint::kStroke_Style);
    pAlphaGray.setColor(0x66888888);

    // Prepare bitmap, and a canvas that draws into it.
    bitmap->reset();
    bitmap->setConfig(SkBitmap::kARGB_8888_Config,
                      quarterWidth*4, quarterHeight*4);
    bitmap->allocPixels();
    SkCanvas canvas(*bitmap);

    SkScalar w = SkIntToScalar(quarterWidth);
    SkScalar h = SkIntToScalar(quarterHeight);
    canvas.drawRectCoords(  0,   0, w*2, h*2, pRed);
    canvas.drawRectCoords(w*2,   0, w*4, h*2, pGreen);
    canvas.drawRectCoords(  0, h*2, w*2, h*4, pBlue);
    canvas.drawRectCoords(w*2, h*2, w*4, h*4, pWhite);
    canvas.drawRectCoords(w, h, w*3, h*3, pAlphaGray);
    canvas.drawLine(w*2,   0, w*2, h*4, pLine);
    canvas.drawLine(  0, h*2, w*4, h*2, pLine);
    canvas.drawRectCoords(w, h, w*3, h*3, pLine);
}

class BitmapScrollGM : public GM {
public:
    BitmapScrollGM() {
        // Create the original bitmap.
        make_bitmap(quarterWidth, quarterHeight, &origBitmap);
    }

protected:
    virtual SkString onShortName() {
        return SkString("bitmapscroll");
    }

    virtual SkISize onISize() {
      return make_isize(800, 600);
    }

    virtual void onDraw(SkCanvas* canvas) {
        SkIRect scrollCenterRegion = SkIRect::MakeXYWH(
            quarterWidth, quarterHeight, quarterWidth*2+1, quarterHeight*2+1);
        int x = quarterWidth;
        int y = quarterHeight;
        int xSpacing = quarterWidth * 20;
        int ySpacing = quarterHeight * 16;

        // Draw background and left-hand text labels.
        canvas->drawColor(0xFFDDDDDD);
        drawLabel(canvas, "scroll entire bitmap",
                  x, y, x, y + ySpacing);
        drawLabel(canvas, "scroll part of bitmap",
                  x, y + ySpacing, x, y + ySpacing*2);
        x += 30;

        // Draw various permutations of scrolled bitmaps, scrolling a bit
        // further each time.
        draw9(canvas, x, y, NULL, quarterWidth*1/2, quarterHeight*1/2);
        draw9(canvas, x, y+ySpacing, &scrollCenterRegion,
              quarterWidth*1/2, quarterHeight*1/2);
        x += xSpacing;
        draw9(canvas, x, y, NULL, quarterWidth*3/2, quarterHeight*3/2);
        draw9(canvas, x, y+ySpacing, &scrollCenterRegion,
              quarterWidth*3/2, quarterHeight*3/2);
        x += xSpacing;
        draw9(canvas, x, y, NULL, quarterWidth*5/2, quarterHeight*5/2);
        draw9(canvas, x, y+ySpacing, &scrollCenterRegion,
              quarterWidth*5/2, quarterHeight*5/2);
        x += xSpacing;
        draw9(canvas, x, y, NULL, quarterWidth*9/2, quarterHeight*9/2);
        draw9(canvas, x, y+ySpacing, &scrollCenterRegion,
              quarterWidth*9/2, quarterHeight*9/2);
    }

    void drawLabel(SkCanvas* canvas, const char *text, int startX, int startY,
                 int endX, int endY) {
        SkPaint paint;
        paint.setColor(0xFF000000);
        SkPath path;
        path.moveTo(SkIntToScalar(startX), SkIntToScalar(startY));
        path.lineTo(SkIntToScalar(endX), SkIntToScalar(endY));
        canvas->drawTextOnPath(text, strlen(text), path, NULL, paint);
    }

    /** Stamp out 9 copies of origBitmap, scrolled in each direction (and
     *  not scrolled at all).
     */
    void draw9(SkCanvas* canvas, int x, int y, SkIRect* subset,
               int scrollX, int scrollY) {
        for (int yMult=-1; yMult<=1; yMult++) {
            for (int xMult=-1; xMult<=1; xMult++) {
                // Figure out the (x,y) to draw this copy at
                SkScalar bitmapX = SkIntToScalar(
                    x + quarterWidth * 5 * (xMult+1));
                SkScalar bitmapY = SkIntToScalar(
                    y + quarterHeight * 5 * (yMult+1));

                // Scroll a new copy of the bitmap, and then draw it.
                // scrollRect() should always return true, even if it's a no-op
                SkBitmap scrolledBitmap;
                SkASSERT(origBitmap.copyTo(
                    &scrolledBitmap, origBitmap.config()));
                SkASSERT(scrolledBitmap.scrollRect(
                    subset, scrollX * xMult, scrollY * yMult));
                canvas->drawBitmap(scrolledBitmap, bitmapX, bitmapY);
            }
        }
    }

private:
    typedef GM INHERITED;
    static const int quarterWidth = 10;
    static const int quarterHeight = 14;
    SkBitmap origBitmap;
};

//////////////////////////////////////////////////////////////////////////////

static GM* MyFactory(void*) { return new BitmapScrollGM; }
static GMRegistry reg(MyFactory);

}
<commit_msg>Fix gm/bitmapscroll.cpp to actually draw in both Debug and Release modes. Review URL: http://codereview.appspot.com/4922047<commit_after>
/*
 * Copyright 2011 Google Inc.
 *
 * Use of this source code is governed by a BSD-style license that can be
 * found in the LICENSE file.
 */
#include "gm.h"

namespace skiagm {

/** Create a bitmap image suitable for testing SkBitmap::scrollRect().
 *
 *  @param quarterWidth bitmap will be 4x this many pixels wide
 *  @param quarterHeight bitmap will be 4x this many pixels tall
 *  @param bitmap the bitmap data is written into this object
 */
static void make_bitmap(int quarterWidth, int quarterHeight, SkBitmap *bitmap) {
    SkPaint pRed, pWhite, pGreen, pBlue, pLine, pAlphaGray;
    pRed.setColor(0xFFFF9999);
    pWhite.setColor(0xFFFFFFFF);
    pGreen.setColor(0xFF99FF99);
    pBlue.setColor(0xFF9999FF);
    pLine.setColor(0xFF000000);
    pLine.setStyle(SkPaint::kStroke_Style);
    pAlphaGray.setColor(0x66888888);

    // Prepare bitmap, and a canvas that draws into it.
    bitmap->reset();
    bitmap->setConfig(SkBitmap::kARGB_8888_Config,
                      quarterWidth*4, quarterHeight*4);
    bitmap->allocPixels();
    SkCanvas canvas(*bitmap);

    SkScalar w = SkIntToScalar(quarterWidth);
    SkScalar h = SkIntToScalar(quarterHeight);
    canvas.drawRectCoords(  0,   0, w*2, h*2, pRed);
    canvas.drawRectCoords(w*2,   0, w*4, h*2, pGreen);
    canvas.drawRectCoords(  0, h*2, w*2, h*4, pBlue);
    canvas.drawRectCoords(w*2, h*2, w*4, h*4, pWhite);
    canvas.drawRectCoords(w, h, w*3, h*3, pAlphaGray);
    canvas.drawLine(w*2,   0, w*2, h*4, pLine);
    canvas.drawLine(  0, h*2, w*4, h*2, pLine);
    canvas.drawRectCoords(w, h, w*3, h*3, pLine);
}

class BitmapScrollGM : public GM {
public:
    BitmapScrollGM() {
        // Create the original bitmap.
        make_bitmap(quarterWidth, quarterHeight, &origBitmap);
    }

protected:
    virtual SkString onShortName() {
        return SkString("bitmapscroll");
    }

    virtual SkISize onISize() {
      return make_isize(800, 600);
    }

    virtual void onDraw(SkCanvas* canvas) {
        SkIRect scrollCenterRegion = SkIRect::MakeXYWH(
            quarterWidth, quarterHeight, quarterWidth*2+1, quarterHeight*2+1);
        int x = quarterWidth;
        int y = quarterHeight;
        int xSpacing = quarterWidth * 20;
        int ySpacing = quarterHeight * 16;

        // Draw background and left-hand text labels.
        canvas->drawColor(0xFFDDDDDD);
        drawLabel(canvas, "scroll entire bitmap",
                  x, y, x, y + ySpacing);
        drawLabel(canvas, "scroll part of bitmap",
                  x, y + ySpacing, x, y + ySpacing*2);
        x += 30;

        // Draw various permutations of scrolled bitmaps, scrolling a bit
        // further each time.
        draw9(canvas, x, y, NULL, quarterWidth*1/2, quarterHeight*1/2);
        draw9(canvas, x, y+ySpacing, &scrollCenterRegion,
              quarterWidth*1/2, quarterHeight*1/2);
        x += xSpacing;
        draw9(canvas, x, y, NULL, quarterWidth*3/2, quarterHeight*3/2);
        draw9(canvas, x, y+ySpacing, &scrollCenterRegion,
              quarterWidth*3/2, quarterHeight*3/2);
        x += xSpacing;
        draw9(canvas, x, y, NULL, quarterWidth*5/2, quarterHeight*5/2);
        draw9(canvas, x, y+ySpacing, &scrollCenterRegion,
              quarterWidth*5/2, quarterHeight*5/2);
        x += xSpacing;
        draw9(canvas, x, y, NULL, quarterWidth*9/2, quarterHeight*9/2);
        draw9(canvas, x, y+ySpacing, &scrollCenterRegion,
              quarterWidth*9/2, quarterHeight*9/2);
    }

    void drawLabel(SkCanvas* canvas, const char *text, int startX, int startY,
                 int endX, int endY) {
        SkPaint paint;
        paint.setColor(0xFF000000);
        SkPath path;
        path.moveTo(SkIntToScalar(startX), SkIntToScalar(startY));
        path.lineTo(SkIntToScalar(endX), SkIntToScalar(endY));
        canvas->drawTextOnPath(text, strlen(text), path, NULL, paint);
    }

    /** Stamp out 9 copies of origBitmap, scrolled in each direction (and
     *  not scrolled at all).
     */
    void draw9(SkCanvas* canvas, int x, int y, SkIRect* subset,
               int scrollX, int scrollY) {
        for (int yMult=-1; yMult<=1; yMult++) {
            for (int xMult=-1; xMult<=1; xMult++) {
                // Figure out the (x,y) to draw this copy at
                SkScalar bitmapX = SkIntToScalar(
                    x + quarterWidth * 5 * (xMult+1));
                SkScalar bitmapY = SkIntToScalar(
                    y + quarterHeight * 5 * (yMult+1));

                // Scroll a new copy of the bitmap, and then draw it.
                // scrollRect() should always return true, even if it's a no-op
                SkBitmap scrolledBitmap;
                bool copyToReturnValue = origBitmap.copyTo(
                    &scrolledBitmap, origBitmap.config());
                SkASSERT(copyToReturnValue);
                bool scrollRectReturnValue = scrolledBitmap.scrollRect(
                    subset, scrollX * xMult, scrollY * yMult);
                SkASSERT(scrollRectReturnValue);
                canvas->drawBitmap(scrolledBitmap, bitmapX, bitmapY);
            }
        }
    }

private:
    typedef GM INHERITED;
    static const int quarterWidth = 10;
    static const int quarterHeight = 14;
    SkBitmap origBitmap;
};

//////////////////////////////////////////////////////////////////////////////

static GM* MyFactory(void*) { return new BitmapScrollGM; }
static GMRegistry reg(MyFactory);

}
<|endoftext|>