<commit_before>#include "TestRunner.h"
#include <atomic>
#include <future>
#include <limits>
#include <mutex>
#include <random>
#include <vector>
#include "DefaultReporter.h"
#include "Fact.h"
#include "TestCollection.h"
#include "TestDetails.h"
#include "xUnitAssert.h"

namespace
{

class ActiveTests
{
public:
    struct TestInstance
    {
        TestInstance(const xUnitpp::TestDetails &testDetails, int id, int groupId, int groupSize, std::function<void()> test)
            : testDetails(testDetails)
            , id(id)
            , groupId(groupId)
            , groupSize(groupSize)
            , test(test)
        {
        }

        TestInstance(const TestInstance &other)
            : testDetails(other.testDetails)
            , id(other.id)
            , groupId(other.groupId)
            , groupSize(other.groupSize)
            , test(other.test)
        {
        }

        TestInstance(TestInstance &&other)
        {
            swap(*this, other);
        }

        TestInstance &operator =(TestInstance other)
        {
            swap(*this, other);
            return *this;
        }

        friend void swap(TestInstance &ti0, TestInstance &ti1)
        {
            using std::swap;

            swap(ti0.testDetails, ti1.testDetails);
            swap(ti0.id, ti1.id);
            swap(ti0.groupId, ti1.groupId);
            swap(ti0.groupSize, ti1.groupSize);
            swap(ti0.test, ti1.test);
        }

        xUnitpp::TestDetails testDetails;

        size_t id;
        size_t groupId;
        size_t groupSize;

        std::function<void()> test;
    };

    ActiveTests(const std::vector<xUnitpp::Fact> &facts, const std::vector<xUnitpp::Theory> &theories, const std::string &suite)
    {
        size_t id = 0;
        size_t groupId = 0;

        for (auto &fact : facts)
        {
            if (suite == "" || fact.TestDetails().Suite == suite)
            {
                mTests.emplace_back(TestInstance(fact.TestDetails(), ++id, ++groupId, 1, fact.Test()));
            }
        }

        for (auto &theorySet : theories)
        {
            if (suite == "" || theorySet.TestDetails().Suite == suite)
            {
                ++groupId;

                for (auto &theory : theorySet.Theories())
                {
                    mTests.emplace_back(TestInstance(theorySet.TestDetails(), ++id, groupId, theorySet.Theories().size(), theory));
                }
            }
        }

        std::shuffle(mTests.begin(), mTests.end(), std::default_random_engine(std::random_device()()));
    }

    std::vector<TestInstance>::iterator begin()
    {
        return mTests.begin();
    }

    std::vector<TestInstance>::iterator end()
    {
        return mTests.end();
    }

private:
    std::vector<TestInstance> mTests;
};

}

namespace xUnitpp
{

class TestRunner::Impl
{
public:
    Impl(std::function<void(const TestDetails &)> onTestStart,
         std::function<void(const TestDetails &, const std::string &)> onTestFailure,
         std::function<void(const TestDetails &, std::chrono::milliseconds)> onTestFinish,
         std::function<void(int, int, int, std::chrono::milliseconds)> onAllTestsComplete)
        : mOnTestStart(onTestStart)
        , mOnTestFailure(onTestFailure)
        , mOnTestFinish(onTestFinish)
        , mOnAllTestsComplete(onAllTestsComplete)
    {
    }

    void OnTestStart(const TestDetails &details)
    {
        std::lock_guard<std::mutex> guard(mStartMtx);
        mOnTestStart(details);
    }

    void OnTestFailure(const TestDetails &details, const std::string &message)
    {
        std::lock_guard<std::mutex> guard(mFailureMtx);
        mOnTestFailure(details, message);
    }

    void OnTestFinish(const TestDetails &details, std::chrono::milliseconds time)
    {
        std::lock_guard<std::mutex> guard(mFinishMtx);
        mOnTestFinish(details, time);
    }

    void OnAllTestsComplete(int total, int skipped, int failed, std::chrono::milliseconds totalTime)
    {
        mOnAllTestsComplete(total, skipped, failed, totalTime);
    }

private:
    std::function<void(const TestDetails &)> mOnTestStart;
    std::function<void(const TestDetails &, const std::string &)> mOnTestFailure;
    std::function<void(const TestDetails &, std::chrono::milliseconds)> mOnTestFinish;
    std::function<void(int, int, int, std::chrono::milliseconds)> mOnAllTestsComplete;

    std::mutex mStartMtx;
    std::mutex mFailureMtx;
    std::mutex mFinishMtx;
};

size_t RunAllTests(const std::string &suite)
{
    return RunAllTests(suite, std::chrono::milliseconds::zero());
}

size_t RunAllTests(std::chrono::milliseconds maxTestRunTime)
{
    return RunAllTests("", maxTestRunTime);
}

size_t RunAllTests(const std::string &suite, std::chrono::milliseconds maxTestRunTime, size_t maxConcurrent)
{
    return
        TestRunner(&DefaultReporter::ReportStart,
                   &DefaultReporter::ReportFailure,
                   &DefaultReporter::ReportFinish,
                   &DefaultReporter::ReportAllTestsComplete)
            .RunTests(TestCollection::Facts(), TestCollection::Theories(), suite, maxTestRunTime, maxConcurrent);
}

TestRunner::TestRunner(std::function<void(const TestDetails &)> onTestStart,
                       std::function<void(const TestDetails &, const std::string &)> onTestFailure,
                       std::function<void(const TestDetails &, std::chrono::milliseconds)> onTestFinish,
                       std::function<void(int, int, int, std::chrono::milliseconds)> onAllTestsComplete)
    : mImpl(new Impl(onTestStart, onTestFailure, onTestFinish, onAllTestsComplete))
{
}

size_t TestRunner::RunTests(const std::vector<Fact> &facts, const std::vector<Theory> &theories, const std::string &suite, std::chrono::milliseconds maxTestRunTime, size_t maxConcurrent)
{
    auto timeStart = std::chrono::system_clock::now();

    ActiveTests activeTests(facts, theories, suite);

    if (maxConcurrent == 0)
    {
        maxConcurrent = std::numeric_limits<decltype(maxConcurrent)>::max();
    }

    class ThreadCounter
    {
    public:
        ThreadCounter(size_t maxThreads)
            : maxThreads(maxThreads)
            , activeThreads(0)
        {
        }

        void operator++()
        {
            std::unique_lock<std::mutex> lock(mtx);
            condition.wait(lock, [&]() { return activeThreads < maxThreads; });

            ++activeThreads;
        }

        void operator--()
        {
            std::lock_guard<std::mutex> guard(mtx);
            --activeThreads;
        }

    private:
        size_t maxThreads;
        size_t activeThreads;
        std::mutex mtx;
        std::condition_variable condition;
    } threadCounter(maxConcurrent);

    std::atomic<size_t> failedTests = 0;

    std::vector<std::future<void>> futures;
    for (auto &test : activeTests)
    {
        futures.push_back(std::async([&]()
            {
                struct CounterGuard
                {
                    CounterGuard(ThreadCounter &tc)
                        : tc(tc)
                    {
                        ++tc;
                    }

                    ~CounterGuard()
                    {
                        --tc;
                    }

                private:
                    ThreadCounter &tc;
                } counterGuard(threadCounter);

                auto actualTest = [&](bool reportEnd) -> TimeStamp
                    {
                        TimeStamp testStart;
                        try
                        {
                            mImpl->OnTestStart(test.testDetails);

                            testStart = Clock::now();
                            test.test();
                        }
                        catch (std::exception &e)
                        {
                            mImpl->OnTestFailure(test.testDetails, e.what());
                            ++failedTests;
                        }
                        catch (...)
                        {
                            mImpl->OnTestFailure(test.testDetails, "Unknown exception caught: test has crashed");
                            ++failedTests;
                        }

                        if (reportEnd)
                        {
                            mImpl->OnTestFinish(test.testDetails, std::chrono::duration_cast<std::chrono::milliseconds>(Clock::now() - testStart));
                        }

                        return testStart;
                    };

                auto testTimeLimit = test.testDetails.TimeLimit;
                if (testTimeLimit < std::chrono::milliseconds::zero())
                {
                    testTimeLimit = maxTestRunTime;
                }

                if (testTimeLimit > std::chrono::milliseconds::zero())
                {
                    //
                    // note that forcing a test to run in under a certain amount of time is inherently fragile
                    // there's no guarantee that a thread, once started, actually gets `maxTestRunTime` milliseconds of CPU

                    TimeStamp testStart;

                    std::mutex m;
                    std::unique_lock<std::mutex> gate(m);

                    std::condition_variable threadStarted;
                    std::thread timedRunner([&]()
                        {
                            m.lock();
                            m.unlock();

                            testStart = actualTest(false);
                            threadStarted.notify_all();
                        });
                    timedRunner.detach();

                    if (threadStarted.wait_for(gate, testTimeLimit) == std::cv_status::timeout)
                    {
                        mImpl->OnTestFailure(test.testDetails, "Test failed to complete within " + std::to_string(testTimeLimit.count()) + " milliseconds.");
                        mImpl->OnTestFinish(test.testDetails, testTimeLimit);
                        ++failedTests;
                    }
                    else
                    {
                        mImpl->OnTestFinish(test.testDetails, std::chrono::duration_cast<std::chrono::milliseconds>(Clock::now() - testStart));
                    }
                }
                else
                {
                    actualTest(true);
                }
            }));
    }

    for (auto &test : futures)
    {
        test.get();
    }

    mImpl->OnAllTestsComplete(futures.size(), failedTests, 0, std::chrono::duration_cast<std::chrono::milliseconds>(Clock::now() - timeStart));

    return failedTests;
}

}
<commit_msg>fixed a crash in the test runner due to the condition_variable getting destroyed by the parent thread exiting<commit_after>#include "TestRunner.h"
#include <atomic>
#include <future>
#include <limits>
#include <mutex>
#include <random>
#include <vector>
#include "DefaultReporter.h"
#include "Fact.h"
#include "TestCollection.h"
#include "TestDetails.h"
#include "xUnitAssert.h"

namespace
{

class ActiveTests
{
public:
    struct TestInstance
    {
        TestInstance(const xUnitpp::TestDetails &testDetails, int id, int groupId, int groupSize, std::function<void()> test)
            : testDetails(testDetails)
            , id(id)
            , groupId(groupId)
            , groupSize(groupSize)
            , test(test)
        {
        }

        TestInstance(const TestInstance &other)
            : testDetails(other.testDetails)
            , id(other.id)
            , groupId(other.groupId)
            , groupSize(other.groupSize)
            , test(other.test)
        {
        }

        TestInstance(TestInstance &&other)
        {
            swap(*this, other);
        }

        TestInstance &operator =(TestInstance other)
        {
            swap(*this, other);
            return *this;
        }

        friend void swap(TestInstance &ti0, TestInstance &ti1)
        {
            using std::swap;

            swap(ti0.testDetails, ti1.testDetails);
            swap(ti0.id, ti1.id);
            swap(ti0.groupId, ti1.groupId);
            swap(ti0.groupSize, ti1.groupSize);
            swap(ti0.test, ti1.test);
        }

        xUnitpp::TestDetails testDetails;

        size_t id;
        size_t groupId;
        size_t groupSize;

        std::function<void()> test;
    };

    ActiveTests(const std::vector<xUnitpp::Fact> &facts, const std::vector<xUnitpp::Theory> &theories, const std::string &suite)
    {
        size_t id = 0;
        size_t groupId = 0;

        for (auto &fact : facts)
        {
            if (suite == "" || fact.TestDetails().Suite == suite)
            {
                mTests.emplace_back(TestInstance(fact.TestDetails(), ++id, ++groupId, 1, fact.Test()));
            }
        }

        for (auto &theorySet : theories)
        {
            if (suite == "" || theorySet.TestDetails().Suite == suite)
            {
                ++groupId;

                for (auto &theory : theorySet.Theories())
                {
                    mTests.emplace_back(TestInstance(theorySet.TestDetails(), ++id, groupId, theorySet.Theories().size(), theory));
                }
            }
        }

        std::shuffle(mTests.begin(), mTests.end(), std::default_random_engine(std::random_device()()));
    }

    std::vector<TestInstance>::iterator begin()
    {
        return mTests.begin();
    }

    std::vector<TestInstance>::iterator end()
    {
        return mTests.end();
    }

private:
    std::vector<TestInstance> mTests;
};

}

namespace xUnitpp
{

class TestRunner::Impl
{
public:
    Impl(std::function<void(const TestDetails &)> onTestStart,
         std::function<void(const TestDetails &, const std::string &)> onTestFailure,
         std::function<void(const TestDetails &, std::chrono::milliseconds)> onTestFinish,
         std::function<void(int, int, int, std::chrono::milliseconds)> onAllTestsComplete)
        : mOnTestStart(onTestStart)
        , mOnTestFailure(onTestFailure)
        , mOnTestFinish(onTestFinish)
        , mOnAllTestsComplete(onAllTestsComplete)
    {
    }

    void OnTestStart(const TestDetails &details)
    {
        std::lock_guard<std::mutex> guard(mStartMtx);
        mOnTestStart(details);
    }

    void OnTestFailure(const TestDetails &details, const std::string &message)
    {
        std::lock_guard<std::mutex> guard(mFailureMtx);
        mOnTestFailure(details, message);
    }

    void OnTestFinish(const TestDetails &details, std::chrono::milliseconds time)
    {
        std::lock_guard<std::mutex> guard(mFinishMtx);
        mOnTestFinish(details, time);
    }

    void OnAllTestsComplete(int total, int skipped, int failed, std::chrono::milliseconds totalTime)
    {
        mOnAllTestsComplete(total, skipped, failed, totalTime);
    }

private:
    std::function<void(const TestDetails &)> mOnTestStart;
    std::function<void(const TestDetails &, const std::string &)> mOnTestFailure;
    std::function<void(const TestDetails &, std::chrono::milliseconds)> mOnTestFinish;
    std::function<void(int, int, int, std::chrono::milliseconds)> mOnAllTestsComplete;

    std::mutex mStartMtx;
    std::mutex mFailureMtx;
    std::mutex mFinishMtx;
};

size_t RunAllTests(const std::string &suite)
{
    return RunAllTests(suite, std::chrono::milliseconds::zero());
}

size_t RunAllTests(std::chrono::milliseconds maxTestRunTime)
{
    return RunAllTests("", maxTestRunTime);
}

size_t RunAllTests(const std::string &suite, std::chrono::milliseconds maxTestRunTime, size_t maxConcurrent)
{
    return
        TestRunner(&DefaultReporter::ReportStart,
                   &DefaultReporter::ReportFailure,
                   &DefaultReporter::ReportFinish,
                   &DefaultReporter::ReportAllTestsComplete)
            .RunTests(TestCollection::Facts(), TestCollection::Theories(), suite, maxTestRunTime, maxConcurrent);
}

TestRunner::TestRunner(std::function<void(const TestDetails &)> onTestStart,
                       std::function<void(const TestDetails &, const std::string &)> onTestFailure,
                       std::function<void(const TestDetails &, std::chrono::milliseconds)> onTestFinish,
                       std::function<void(int, int, int, std::chrono::milliseconds)> onAllTestsComplete)
    : mImpl(new Impl(onTestStart, onTestFailure, onTestFinish, onAllTestsComplete))
{
}

size_t TestRunner::RunTests(const std::vector<Fact> &facts, const std::vector<Theory> &theories, const std::string &suite, std::chrono::milliseconds maxTestRunTime, size_t maxConcurrent)
{
    auto timeStart = std::chrono::system_clock::now();

    ActiveTests activeTests(facts, theories, suite);

    if (maxConcurrent == 0)
    {
        maxConcurrent = std::numeric_limits<decltype(maxConcurrent)>::max();
    }

    class ThreadCounter
    {
    public:
        ThreadCounter(size_t maxThreads)
            : maxThreads(maxThreads)
            , activeThreads(0)
        {
        }

        void operator++()
        {
            std::unique_lock<std::mutex> lock(mtx);
            condition.wait(lock, [&]() { return activeThreads < maxThreads; });

            ++activeThreads;
        }

        void operator--()
        {
            std::lock_guard<std::mutex> guard(mtx);
            --activeThreads;
        }

    private:
        size_t maxThreads;
        size_t activeThreads;
        std::mutex mtx;
        std::condition_variable condition;
    } threadCounter(maxConcurrent);

    std::atomic<size_t> failedTests = 0;

    std::vector<std::future<void>> futures;
    for (auto &test : activeTests)
    {
        futures.push_back(std::async([&]()
            {
                struct CounterGuard
                {
                    CounterGuard(ThreadCounter &tc)
                        : tc(tc)
                    {
                        ++tc;
                    }

                    ~CounterGuard()
                    {
                        --tc;
                    }

                private:
                    ThreadCounter &tc;
                } counterGuard(threadCounter);

                auto actualTest = [&](bool reportEnd) -> TimeStamp
                    {
                        TimeStamp testStart;
                        try
                        {
                            mImpl->OnTestStart(test.testDetails);

                            testStart = Clock::now();
                            test.test();
                        }
                        catch (std::exception &e)
                        {
                            mImpl->OnTestFailure(test.testDetails, e.what());
                            ++failedTests;
                        }
                        catch (...)
                        {
                            mImpl->OnTestFailure(test.testDetails, "Unknown exception caught: test has crashed");
                            ++failedTests;
                        }

                        if (reportEnd)
                        {
                            mImpl->OnTestFinish(test.testDetails, std::chrono::duration_cast<std::chrono::milliseconds>(Clock::now() - testStart));
                        }

                        return testStart;
                    };

                auto testTimeLimit = test.testDetails.TimeLimit;
                if (testTimeLimit < std::chrono::milliseconds::zero())
                {
                    testTimeLimit = maxTestRunTime;
                }

                if (testTimeLimit > std::chrono::milliseconds::zero())
                {
                    //
                    // note that forcing a test to run in under a certain amount of time is inherently fragile
                    // there's no guarantee that a thread, once started, actually gets `maxTestRunTime` milliseconds of CPU

                    TimeStamp testStart;

                    std::mutex m;
                    std::unique_lock<std::mutex> gate(m);

                    auto threadStarted = std::make_shared<std::condition_variable>();
                    std::thread timedRunner([&, threadStarted]()
                        {
                            m.lock();
                            m.unlock();

                            testStart = actualTest(false);
                            threadStarted->notify_all();
                        });
                    timedRunner.detach();

                    if (threadStarted->wait_for(gate, testTimeLimit) == std::cv_status::timeout)
                    {
                        mImpl->OnTestFailure(test.testDetails, "Test failed to complete within " + std::to_string(testTimeLimit.count()) + " milliseconds.");
                        mImpl->OnTestFinish(test.testDetails, testTimeLimit);
                        ++failedTests;
                    }
                    else
                    {
                        mImpl->OnTestFinish(test.testDetails, std::chrono::duration_cast<std::chrono::milliseconds>(Clock::now() - testStart));
                    }
                }
                else
                {
                    actualTest(true);
                }
            }));
    }

    for (auto &test : futures)
    {
        test.get();
    }

    mImpl->OnAllTestsComplete(futures.size(), failedTests, 0, std::chrono::duration_cast<std::chrono::milliseconds>(Clock::now() - timeStart));

    return failedTests;
}

}
<|endoftext|>


<commit_before>/*
 NUI3 - C++ cross-platform GUI framework for OpenGL based applications
 Copyright (C) 2002-2003 Sebastien Metrot

 licence: see nui3/LICENCE.TXT
 */

#include "nui.h"
#include "nuiAttributeAnimation.h"

//class nuiAttributeAnimation : public nuiAnimation
nuiAttributeAnimation::nuiAttributeAnimation()
: mStartValue(0),
  mEndValue(0),
  mCaptureStartOnPlay(false),
  mCaptureEndOnPlay(false),
  mpTarget(NULL)
{
}

nuiAttributeAnimation::~nuiAttributeAnimation()
{
}

nuiObjectPtr nuiAttributeAnimation::GetTargetObject() const
{
  return mpTarget;
}

void nuiAttributeAnimation::SetTargetObject(nuiObjectPtr pTarget)
{
  mpTarget = pTarget;
}

const nglString& nuiAttributeAnimation::GetTargetAttribute() const
{
  return mTarget;
}

void nuiAttributeAnimation::SetTargetAttribute(const nglString& rAttribute)
{
  mTarget = rAttribute;
}

void nuiAttributeAnimation::SetCaptureStartOnPlay(bool set)
{
  mCaptureStartOnPlay = set;
}

bool nuiAttributeAnimation::GetCaptureStartOnPlay() const
{
  return mCaptureStartOnPlay;
}

void nuiAttributeAnimation::SetCaptureEndOnPlay(bool set)
{
  mCaptureEndOnPlay = set;
}

bool nuiAttributeAnimation::GetCaptureEndOnPlay() const
{
  return mCaptureEndOnPlay;
}

void nuiAttributeAnimation::SetStartValue(double val)
{
  mStartValue = val;
}

double nuiAttributeAnimation::GetStartValue() const
{
  return mStartValue;
}

void nuiAttributeAnimation::SetEndValue(double val)
{
  mEndValue = val;
}

double nuiAttributeAnimation::GetEndValue() const
{
  return mEndValue;
}

void nuiAttributeAnimation::Play(uint32 Count, nuiAnimLoop LoopMode)
{
  if (mCaptureStartOnPlay)
  {
    nuiAttribBase attrib(mpTarget->GetAttribute(mTarget));
    nglString str;
    if (attrib.ToString(str))
      mStartValue = str.GetCDouble();
  }
  if (mCaptureEndOnPlay)
  {
    nuiAttribBase attrib(mpTarget->GetAttribute(mTarget));
    nglString str;
    if (attrib.ToString(str))
      mEndValue = str.GetCDouble();
  }

  nuiAnimation::Play(Count, LoopMode);
}

void nuiAttributeAnimation::Stop()
{
  nuiAnimation::Stop();
}

#define SET_ATTRIB(X) \
nuiAttrib<X> attrib_##X(attrib); \
if (attrib_##X.IsValid()) \
{ \
  attrib_##X.Set(pos); \
  return; \
}

void nuiAttributeAnimation::OnFrame()
{
  double pos = mStartValue + GetPosition() * (mEndValue - mStartValue);
  nuiAttribBase attrib(mpTarget->GetAttribute(mTarget));
  if (!attrib.IsValid() || attrib.IsReadOnly())
    return;

  SET_ATTRIB(float);
  SET_ATTRIB(double);
  SET_ATTRIB(int32);
  SET_ATTRIB(uint32);
  SET_ATTRIB(int64);
  SET_ATTRIB(uint64);
  SET_ATTRIB(int16);
  SET_ATTRIB(uint16);
  SET_ATTRIB(int8);
  SET_ATTRIB(uint8);

  nglString str;
  str.SetCDouble(pos);
  attrib.FromString(str);
}

<commit_msg>better anim<commit_after>/*
 NUI3 - C++ cross-platform GUI framework for OpenGL based applications
 Copyright (C) 2002-2003 Sebastien Metrot

 licence: see nui3/LICENCE.TXT
 */

#include "nui.h"
#include "nuiAttributeAnimation.h"

//class nuiAttributeAnimation : public nuiAnimation
nuiAttributeAnimation::nuiAttributeAnimation()
: mStartValue(0),
  mEndValue(0),
  mCaptureStartOnPlay(false),
  mCaptureEndOnPlay(false),
  mpTarget(NULL)
{
}

nuiAttributeAnimation::~nuiAttributeAnimation()
{
}

nuiObjectPtr nuiAttributeAnimation::GetTargetObject() const
{
  return mpTarget;
}

void nuiAttributeAnimation::SetTargetObject(nuiObjectPtr pTarget)
{
  mpTarget = pTarget;
}

const nglString& nuiAttributeAnimation::GetTargetAttribute() const
{
  return mTarget;
}

void nuiAttributeAnimation::SetTargetAttribute(const nglString& rAttribute)
{
  mTarget = rAttribute;
}

void nuiAttributeAnimation::SetCaptureStartOnPlay(bool set)
{
  mCaptureStartOnPlay = set;
}

bool nuiAttributeAnimation::GetCaptureStartOnPlay() const
{
  return mCaptureStartOnPlay;
}

void nuiAttributeAnimation::SetCaptureEndOnPlay(bool set)
{
  mCaptureEndOnPlay = set;
}

bool nuiAttributeAnimation::GetCaptureEndOnPlay() const
{
  return mCaptureEndOnPlay;
}

void nuiAttributeAnimation::SetStartValue(double val)
{
  mStartValue = val;
}

double nuiAttributeAnimation::GetStartValue() const
{
  return mStartValue;
}

void nuiAttributeAnimation::SetEndValue(double val)
{
  mEndValue = val;
}

double nuiAttributeAnimation::GetEndValue() const
{
  return mEndValue;
}

void nuiAttributeAnimation::Play(uint32 Count, nuiAnimLoop LoopMode)
{
  if (mCaptureStartOnPlay)
  {
    nuiAttribBase attrib(mpTarget->GetAttribute(mTarget));
    nglString str;
    if (attrib.ToString(str))
      mStartValue = str.GetCDouble();
  }
  if (mCaptureEndOnPlay)
  {
    nuiAttribBase attrib(mpTarget->GetAttribute(mTarget));
    nglString str;
    if (attrib.ToString(str))
      mEndValue = str.GetCDouble();
  }

  nuiAnimation::Play(Count, LoopMode);
}

void nuiAttributeAnimation::Stop()
{
  nuiAnimation::Stop();
}

#define SET_ATTRIB(X) \
if (nuiAttributeTypeTrait<X>::GetTypeId() == t) \
{ \
  nuiAttrib<X> attrib_##X(attrib); \
  NGL_ASSERT(attrib_##X.IsValid()); \
  attrib_##X.Set(pos); \
  return; \
}

void nuiAttributeAnimation::OnFrame()
{
  double pos = mStartValue + GetPosition() * (mEndValue - mStartValue);
  nuiAttribBase attrib(mpTarget->GetAttribute(mTarget));
  if (!attrib.IsValid() || attrib.IsReadOnly())
    return;

  nuiAttributeType t = attrib.GetType();
  SET_ATTRIB(float);
  SET_ATTRIB(double);
  SET_ATTRIB(int32);
  SET_ATTRIB(uint32);
  SET_ATTRIB(int64);
  SET_ATTRIB(uint64);
  SET_ATTRIB(int16);
  SET_ATTRIB(uint16);
  SET_ATTRIB(int8);
  SET_ATTRIB(uint8);

  nglString str;
  str.SetCDouble(pos);
  attrib.FromString(str);
}

<|endoftext|>


<commit_before>//=======================================================================
// Copyright (c) 2014-2017 Baptiste Wicht
// Distributed under the terms of the MIT License.
// (See accompanying file LICENSE or copy at
//  http://opensource.org/licenses/MIT)
//=======================================================================

#include <iostream>
#include <chrono>
#include <random>

#define ETL_COUNTERS
#define ETL_COUNTERS_VERBOSE

#define IF_DEBUG if(false)

#include "etl/etl.hpp"

typedef std::chrono::high_resolution_clock timer_clock;
typedef std::chrono::milliseconds milliseconds;

float fake = 0;

/*
 *
 * Current values are (alloc/gpu_to_cpu/cpu_to_gpu):
 * Simple: 3 / 0 / 2 (Optimal!)
 * Basic: 15 / 0 / 3 (Optimal!)
 * Sub: 960 / 640 / 160
 */

void simple(){
    etl::dyn_matrix<float, 2> A(4096, 4096);
    etl::dyn_matrix<float, 2> B(4096, 4096);
    etl::dyn_matrix<float, 2> C(4096, 4096);

    A = 1e-4 >> etl::sequence_generator<float>(1.0);
    B = 1e-4 >> etl::sequence_generator<float>(1.0);
    C = 1e-4 >> etl::sequence_generator<float>(1.0);

    etl::reset_counters();

    std::cout << "Simple" << std::endl;

    for (size_t i = 0; i < 10; ++i) {
        C = A * B;
        fake += etl::mean(C);
    }

    etl::dump_counters();

    std::cout << "   Result: " << fake << std::endl;
    std::cout << "Should be: 2.8826e+10" << std::endl;
}

void basic(){
    etl::dyn_matrix<float, 2> A(4096, 4096);
    etl::dyn_matrix<float, 2> B(4096, 4096);
    etl::dyn_matrix<float, 2> C(4096, 4096);
    etl::dyn_matrix<float, 2> D(4096, 4096);
    etl::dyn_matrix<float, 2> E(4096, 4096);

    A = 1e-4 >> etl::sequence_generator<float>(1.0);
    B = 1e-4 >> etl::sequence_generator<float>(1.0);
    C = 1e-4 >> etl::sequence_generator<float>(1.0);
    D = 1e-4 >> etl::sequence_generator<float>(1.0);
    E = 1e-4 >> etl::sequence_generator<float>(1.0);

    etl::reset_counters();

    std::cout << "Basic" << std::endl;

    for (size_t i = 0; i < 10; ++i) {
        IF_DEBUG std::cout << i << ":0 C = A * B * E" << std::endl;
        C = A * B * E;
        IF_DEBUG std::cout << i << ":1 D = A * trans(A)" << std::endl;
        D = A * trans(A);
        IF_DEBUG std::cout << i << ":2 D *= 1.1" << std::endl;
        D *= 1.1;
        IF_DEBUG std::cout << i << ":3 E = D" << std::endl;
        E = D;
        IF_DEBUG std::cout << i << ":4 D += C" << std::endl;
        D += C;
        IF_DEBUG std::cout << i << ":5 fake += etl::mean(D)" << std::endl;
        fake += etl::mean(D);
        IF_DEBUG std::cout << i << ":6 end" << std::endl;
    }

    etl::dump_counters();

    std::cout << "   Result: " << fake << std::endl;
    std::cout << "Should be: 3.36933e+23" << std::endl;
}

void sub(){
    etl::dyn_matrix<float, 3> A(16, 2048, 2048);
    etl::dyn_matrix<float, 3> B(16, 2048, 2048);
    etl::dyn_matrix<float, 3> C(16, 2048, 2048);
    etl::dyn_matrix<float, 3> D(16, 2048, 2048);

    A = etl::normal_generator<float>(1.0, 0.0);
    B = etl::normal_generator<float>(1.0, 0.0);
    C = etl::normal_generator<float>(1.0, 0.0);
    D = etl::normal_generator<float>(1.0, 0.0);

    etl::reset_counters();

    std::cout << "Sub" << std::endl;

    for (size_t i = 0; i < 10; ++i) {
        for (size_t k = 0; k < 16; ++k) {
            C(k) = A(k) * B(k) * B(k);
            D(k) += C(k);
            D(k) *= 1.1;
            fake += etl::mean(D(k));
        }
    }

    etl::dump_counters();
}

int main(){
    auto start_time = timer_clock::now();

    simple();
    basic();
    sub();

    auto end_time = timer_clock::now();
    auto duration = std::chrono::duration_cast<milliseconds>(end_time - start_time);

    std::cout << "duration: " << duration.count() << "ms" << std::endl;

    return (int) fake;
}
<commit_msg>New GPU counters experiment<commit_after>//=======================================================================
// Copyright (c) 2014-2017 Baptiste Wicht
// Distributed under the terms of the MIT License.
// (See accompanying file LICENSE or copy at
//  http://opensource.org/licenses/MIT)
//=======================================================================

#include <iostream>
#include <chrono>
#include <random>

#define ETL_COUNTERS
#define ETL_COUNTERS_VERBOSE

#define IF_DEBUG if(false)

#include "etl/etl.hpp"

typedef std::chrono::high_resolution_clock timer_clock;
typedef std::chrono::milliseconds milliseconds;

float fake = 0;

/*
 *
 * Current values are (alloc/gpu_to_cpu/cpu_to_gpu):
 * Simple: 3 / 0 / 2 (Optimal!)
 * Basic: 15 / 0 / 3 (Optimal!)
 * Sub: 960 / 640 / 160
 * ML: 960 / 640 / 160
 */

void simple(){
    etl::dyn_matrix<float, 2> A(4096, 4096);
    etl::dyn_matrix<float, 2> B(4096, 4096);
    etl::dyn_matrix<float, 2> C(4096, 4096);

    A = 1e-4 >> etl::sequence_generator<float>(1.0);
    B = 1e-4 >> etl::sequence_generator<float>(1.0);
    C = 1e-4 >> etl::sequence_generator<float>(1.0);

    etl::reset_counters();

    std::cout << "Simple" << std::endl;

    for (size_t i = 0; i < 10; ++i) {
        C = A * B;
        fake += etl::mean(C);
    }

    etl::dump_counters();

    std::cout << "   Result: " << fake << std::endl;
    std::cout << "Should be: 2.8826e+10" << std::endl;
}

void basic(){
    etl::dyn_matrix<float, 2> A(4096, 4096);
    etl::dyn_matrix<float, 2> B(4096, 4096);
    etl::dyn_matrix<float, 2> C(4096, 4096);
    etl::dyn_matrix<float, 2> D(4096, 4096);
    etl::dyn_matrix<float, 2> E(4096, 4096);

    A = 1e-4 >> etl::sequence_generator<float>(1.0);
    B = 1e-4 >> etl::sequence_generator<float>(1.0);
    C = 1e-4 >> etl::sequence_generator<float>(1.0);
    D = 1e-4 >> etl::sequence_generator<float>(1.0);
    E = 1e-4 >> etl::sequence_generator<float>(1.0);

    etl::reset_counters();

    std::cout << "Basic" << std::endl;

    for (size_t i = 0; i < 10; ++i) {
        IF_DEBUG std::cout << i << ":0 C = A * B * E" << std::endl;
        C = A * B * E;
        IF_DEBUG std::cout << i << ":1 D = A * trans(A)" << std::endl;
        D = A * trans(A);
        IF_DEBUG std::cout << i << ":2 D *= 1.1" << std::endl;
        D *= 1.1;
        IF_DEBUG std::cout << i << ":3 E = D" << std::endl;
        E = D;
        IF_DEBUG std::cout << i << ":4 D += C" << std::endl;
        D += C;
        IF_DEBUG std::cout << i << ":5 fake += etl::mean(D)" << std::endl;
        fake += etl::mean(D);
        IF_DEBUG std::cout << i << ":6 end" << std::endl;
    }

    etl::dump_counters();

    std::cout << "   Result: " << fake << std::endl;
    std::cout << "Should be: 3.36933e+23" << std::endl;
}

void sub(){
    etl::dyn_matrix<float, 3> A(16, 2048, 2048);
    etl::dyn_matrix<float, 3> B(16, 2048, 2048);
    etl::dyn_matrix<float, 3> C(16, 2048, 2048);
    etl::dyn_matrix<float, 3> D(16, 2048, 2048);

    A = etl::normal_generator<float>(1.0, 0.0);
    B = etl::normal_generator<float>(1.0, 0.0);
    C = etl::normal_generator<float>(1.0, 0.0);
    D = etl::normal_generator<float>(1.0, 0.0);

    etl::reset_counters();

    std::cout << "Sub" << std::endl;

    for (size_t i = 0; i < 10; ++i) {
        for (size_t k = 0; k < 16; ++k) {
            C(k) = A(k) * B(k) * B(k);
            D(k) += C(k);
            D(k) *= 1.1;
            fake += etl::mean(D(k));
        }
    }

    etl::dump_counters();
}

// Simulate forward propagation in a neural network (with some ops as DLL)
void ml(){
    etl::dyn_matrix<float, 4> I(32, 3, 28, 28);

    etl::dyn_matrix<float, 4> W1(16, 3, 3, 3);
    etl::dyn_matrix<float, 1> B1(16);
    etl::dyn_matrix<float, 4> O1(32, 16, 28, 28);

    etl::dyn_matrix<float, 4> P1(32, 16, 14, 14);

    etl::dyn_matrix<float, 4> W2(16, 16, 3, 3);
    etl::dyn_matrix<float, 1> B2(16);
    etl::dyn_matrix<float, 4> O2(32, 16, 14, 14);

    etl::dyn_matrix<float, 4> P2(32, 16, 7, 7);

    etl::dyn_matrix<float, 2> W3(16 * 7 * 7, 500);
    etl::dyn_matrix<float, 1> B3(500);
    etl::dyn_matrix<float, 2> O3(32, 500);

    etl::dyn_matrix<float, 2> W4(500, 10);
    etl::dyn_matrix<float, 1> B4(10);
    etl::dyn_matrix<float, 2> O4(32, 10);

    etl::reset_counters();

    std::cout << "ML" << std::endl;

    for (size_t i = 0; i < 10; ++i) {
        O1 = bias_add_4d(etl::ml::convolution_forward<1, 1, 1, 1>(I, W1), B1);
        P1 = etl::max_pool_3d<1, 2, 2>(O1);

        O2 = bias_add_4d(etl::ml::convolution_forward<1, 1, 1, 1>(P1, W2), B2);
        P2 = etl::max_pool_3d<1, 2, 2>(O2);

        O3 = bias_add_2d(etl::reshape<32, 16 * 7 * 7>(P2) * W3, B3);
        O4 = bias_add_2d(O3 * W4, B4);

        //TODO Add backward
    }

    etl::dump_counters();
}

int main(){
    auto start_time = timer_clock::now();

    simple();
    basic();
    sub();
    ml();

    auto end_time = timer_clock::now();
    auto duration = std::chrono::duration_cast<milliseconds>(end_time - start_time);

    std::cout << "duration: " << duration.count() << "ms" << std::endl;

    return (int) fake;
}
<|endoftext|>


<commit_before>#include "Shooter.h"
//include commands/(shooting command)

using Shooter = subsystems::Shooter;

Shooter::Shooter() : Subsystem("Shooter")
{
	top_roller_ = new CANTalon(1);
}

Shooter::~Shooter()
{
	delete top_roller_;
}

void Shooter::Initialize()
{
	top_roller_->SetFeedbackDevice(CANTalon::QuadEncoder);
	top_roller_->ConfigEncoderCodesPerRev(1024);
	top_roller_->SetSensorDirection(false);
	top_roller_->SelectProfileSlot(0);
	top_roller_->SetVoltageRampRate(0.0);
	top_roller_->SetCloseLoopRampRate(0.0);

	// Set max and min voltage ouput, dissalows negative voltage
	top_roller_->ConfigNominalOutputVoltage(0.0, 0.0);
	top_roller_->ConfigPeakOutputVoltage(12.0, 0.0);
}

void Shooter::SpinUp(double speed)
{
	double target = top_roller_->Get() * speed;
	top_roller_->Set(target);
}

void Shooter::SpinDown()
{
	top_roller_->Set(0.0);
}

void Shooter::EmergencyStop()
{
	top_roller_->StopMotor();
}
<commit_msg>Adds the implementation of functions, variable checks, and use of states and modes for the subsystem, and the roller's maximum velocity<commit_after>#include "Shooter.h"
#include "Commands/SpinUp.h"
#include "Commands/SpinDown.h"
#include <math.h>

using Shooter = subsystems::Shooter;
using SpinUp = commands::SpinUp;
using SpinDown = commands::SpinDown;

Shooter::Shooter() : Subsystem("Shooter")
{
	top_roller_ = new CANTalon(1);
	allowed_error_ = 0.1;
	state_ = State_t::OFF;
	mode_ = Mode_t::VELOCITY;
	max_velocity_ = 30;
}

Shooter::~Shooter()
{
	delete top_roller_;
}

void Shooter::Initialize()
{
	top_roller_->SetFeedbackDevice(CANTalon::QuadEncoder);
	top_roller_->ConfigEncoderCodesPerRev(1024);
	top_roller_->SetSensorDirection(false);
	top_roller_->SelectProfileSlot(0);
	top_roller_->SetVoltageRampRate(0.0);
	top_roller_->SetCloseLoopRampRate(0.0);

	// Set max and min voltage ouput, dissalows negative voltage
	top_roller_->ConfigNominalOutputVoltage(0.0, 0.0);
	top_roller_->ConfigPeakOutputVoltage(12.0, 0.0);
}

void Shooter::SpinUp(double speed)
{
	double target = top_roller_->Get() * speed;
	top_roller_->Set(target);

	///////////////////HALP////////////////////////

	if (mode_ == Mode_t::VELOCITY)
	{
		top_roller_->Set(max_velocity_ * speed);
	}
	else if (mode_ == Mode_t::VBUS)
	{
		top_roller_->Set(speed);
	}
}

void Shooter::SpinDown()
{
	top_roller_->Set(0.0);
}

void Shooter::EmergencyStop()
{
	top_roller_->StopMotor();
}

double Shooter::GetErr() const
{
	return top_roller_->GetSetpoint() - top_roller_->Get();
}

void Shooter::SetAllowedError(double err)
{
	allowed_error_ = err;
}

double Shooter::GetAllowedError() const
{
	return allowed_error_;
}

bool Shooter::IsAllowable() const
{
	return (fabs(GetErr()) > fabs(allowed_error_));
}

// States and modes or whatever:
Shooter::State_t Shooter::GetState() const
{
	return state_;
}

void Shooter::SetState(State_t state)
{
	state_ = state;
}

double Shooter::GetMaxVelocity() const
{
	return max_velocity_;
}

void Shooter::SetMaxVelocity(double max_velocity)
{
	max_velocity_ = max_velocity;
}

// Command functions:
SpinUp* Shooter::MakeSpinUp()
{
	return new commands::SpinUp(this, 1.0);
}

SpinDown* Shooter::MakeSpinDown()
{
	return new commands::SpinDown(this);
}
<|endoftext|>


<commit_before>/*************************************************************************
 *
 *  $RCSfile: XMLChangeTrackingImportHelper.hxx,v $
 *
 *  $Revision: 1.10 $
 *
 *  last change: $Author: obo $ $Date: 2004-02-16 12:24:44 $
 *
 *  The Contents of this file are made available subject to the terms of
 *  either of the following licenses
 *
 *         - GNU Lesser General Public License Version 2.1
 *         - Sun Industry Standards Source License Version 1.1
 *
 *  Sun Microsystems Inc., October, 2000
 *
 *  GNU Lesser General Public License Version 2.1
 *  =============================================
 *  Copyright 2000 by Sun Microsystems, Inc.
 *  901 San Antonio Road, Palo Alto, CA 94303, USA
 *
 *  This library is free software; you can redistribute it and/or
 *  modify it under the terms of the GNU Lesser General Public
 *  License version 2.1, as published by the Free Software Foundation.
 *
 *  This library is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 *  Lesser General Public License for more details.
 *
 *  You should have received a copy of the GNU Lesser General Public
 *  License along with this library; if not, write to the Free Software
 *  Foundation, Inc., 59 Temple Place, Suite 330, Boston,
 *  MA  02111-1307  USA
 *
 *
 *  Sun Industry Standards Source License Version 1.1
 *  =================================================
 *  The contents of this file are subject to the Sun Industry Standards
 *  Source License Version 1.1 (the "License"); You may not use this file
 *  except in compliance with the License. You may obtain a copy of the
 *  License at http://www.openoffice.org/license.html.
 *
 *  Software provided under this License is provided on an "AS IS" basis,
 *  WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING,
 *  WITHOUT LIMITATION, WARRANTIES THAT THE SOFTWARE IS FREE OF DEFECTS,
 *  MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE, OR NON-INFRINGING.
 *  See the License for the specific provisions governing your rights and
 *  obligations concerning the Software.
 *
 *  The Initial Developer of the Original Code is: Sun Microsystems, Inc.
 *
 *  Copyright: 2000 by Sun Microsystems, Inc.
 *
 *  All Rights Reserved.
 *
 *  Contributor(s): _______________________________________
 *
 *
 ************************************************************************/

#ifndef _SC_XMLCHANGETRACKINGIMPORTHELPER_HXX
#define _SC_XMLCHANGETRACKINGIMPORTHELPER_HXX

#ifndef SC_CHGTRACK_HXX
#include "chgtrack.hxx"
#endif

#ifndef __SGI_STL_LIST
#include <list>
#endif
#ifndef _SAL_TYPES_H_
#include <sal/types.h>
#endif
#ifndef _COM_SUN_STAR_UTIL_DATETIME_HPP_
#include <com/sun/star/util/DateTime.hpp>
#endif

class ScBaseCell;
class ScDocument;
class DateTime;

struct ScMyActionInfo
{
    rtl::OUString sUser;
    rtl::OUString sComment;
    com::sun::star::util::DateTime aDateTime;
};

struct ScMyCellInfo
{
    ScBaseCell*     pCell;
    rtl::OUString   sFormulaAddress;
    rtl::OUString   sFormula;
    String          sInputString;
    double          fValue;
    sal_Int32       nMatrixCols;
    sal_Int32       nMatrixRows;
    sal_uInt16      nType;
    sal_uInt8       nMatrixFlag;

    ScMyCellInfo();
    ScMyCellInfo(ScBaseCell* pCell, const rtl::OUString& sFormulaAddress, const rtl::OUString& sFormula, const rtl::OUString& sInputString,
                const double& fValue, const sal_uInt16 nType, const sal_uInt8 nMatrixFlag, const sal_Int32 nMatrixCols,
                const sal_Int32 nMatrixRows);
    ~ScMyCellInfo();

    ScBaseCell* CreateCell(ScDocument* pDoc);
};

struct ScMyDeleted
{
    sal_uInt32 nID;
    ScMyCellInfo* pCellInfo;

    ScMyDeleted();
    ~ScMyDeleted();
};

typedef std::list<ScMyDeleted*> ScMyDeletedList;

struct ScMyGenerated
{
    ScBigRange      aBigRange;
    sal_uInt32      nID;
    ScMyCellInfo*   pCellInfo;

    ScMyGenerated(ScMyCellInfo* pCellInfo, const ScBigRange& aBigRange);
    ~ScMyGenerated();
};

typedef std::list<ScMyGenerated*> ScMyGeneratedList;

struct ScMyInsertionCutOff
{
    sal_uInt32 nID;
    sal_Int32 nPosition;

    ScMyInsertionCutOff(const sal_uInt32 nTempID, const sal_Int32 nTempPosition) :
            nID(nTempID), nPosition(nTempPosition) {}
};

struct ScMyMoveCutOff
{
    sal_uInt32 nID;
    sal_Int32 nStartPosition;
    sal_Int32 nEndPosition;

    ScMyMoveCutOff(const sal_uInt32 nTempID, const sal_Int32 nStartPos, const sal_Int32 nEndPos) :
            nID(nTempID), nStartPosition(nStartPos), nEndPosition(nEndPos) {}
};

typedef std::list<ScMyMoveCutOff> ScMyMoveCutOffs;

struct ScMyMoveRanges
{
    ScBigRange aSourceRange;
    ScBigRange aTargetRange;

    ScMyMoveRanges(const ScBigRange& aSource, const ScBigRange aTarget) :
            aSourceRange(aSource), aTargetRange(aTarget) {}
};

typedef std::list<sal_uInt32> ScMyDependences;

struct ScMyBaseAction
{
    ScMyActionInfo aInfo;
    ScBigRange aBigRange;
    ScMyDependences aDependences;
    ScMyDeletedList aDeletedList;
    sal_uInt32 nActionNumber;
    sal_uInt32 nRejectingNumber;
    sal_uInt32 nPreviousAction;
    ScChangeActionType nActionType;
    ScChangeActionState nActionState;

    ScMyBaseAction(const ScChangeActionType nActionType);
    ~ScMyBaseAction();
};

struct ScMyInsAction : public ScMyBaseAction
{
    ScMyInsAction(const ScChangeActionType nActionType);
    ~ScMyInsAction();
};

struct ScMyDelAction : public ScMyBaseAction
{
    ScMyGeneratedList aGeneratedList;
    ScMyInsertionCutOff* pInsCutOff;
    ScMyMoveCutOffs aMoveCutOffs;
    sal_Int16 nD;

    ScMyDelAction(const ScChangeActionType nActionType);
    ~ScMyDelAction();
};

struct ScMyMoveAction : public ScMyBaseAction
{
    ScMyGeneratedList aGeneratedList;
    ScMyMoveRanges* pMoveRanges;

    ScMyMoveAction();
    ~ScMyMoveAction();
};

struct ScMyContentAction : public ScMyBaseAction
{
    ScMyCellInfo*   pCellInfo;

    ScMyContentAction();
    ~ScMyContentAction();
};

struct ScMyRejAction : public ScMyBaseAction
{
    ScMyRejAction();
    ~ScMyRejAction();
};

typedef std::list<ScMyBaseAction*> ScMyActions;

class ScChangeViewSettings;

class ScXMLChangeTrackingImportHelper
{
    StrCollection       aUsers;
    ScMyActions         aActions;
    com::sun::star::uno::Sequence<sal_Int8> aProtect;
    ScDocument*         pDoc;
    ScChangeTrack*      pTrack;
    ScMyBaseAction*     pCurrentAction;
    rtl::OUString       sIDPrefix;
    sal_uInt32          nPrefixLength;
    sal_Int16           nMultiSpanned;
    sal_Int16           nMultiSpannedSlaveCount;
    sal_Bool            bChangeTrack : 1;

private:
    void ConvertInfo(const ScMyActionInfo& aInfo, String& rUser, DateTime& aDateTime);
    ScChangeAction* CreateInsertAction(ScMyInsAction* pAction);
    ScChangeAction* CreateDeleteAction(ScMyDelAction* pAction);
    ScChangeAction* CreateMoveAction(ScMyMoveAction* pAction);
    ScChangeAction* CreateRejectionAction(ScMyRejAction* pAction);
    ScChangeAction* CreateContentAction(ScMyContentAction* pAction);

    void CreateGeneratedActions(ScMyGeneratedList& rList);

public:
    ScXMLChangeTrackingImportHelper();
    ~ScXMLChangeTrackingImportHelper();

    void SetChangeTrack(sal_Bool bValue) { bChangeTrack = bValue; }
    void SetProtection(const com::sun::star::uno::Sequence<sal_Int8>& rProtect) { aProtect = rProtect; }
    void StartChangeAction(const ScChangeActionType nActionType);

    sal_uInt32 GetIDFromString(const rtl::OUString& sID);

    void SetActionNumber(const sal_uInt32 nActionNumber) { pCurrentAction->nActionNumber = nActionNumber; }
    void SetActionState(const ScChangeActionState nActionState) { pCurrentAction->nActionState = nActionState; }
    void SetRejectingNumber(const sal_uInt32 nRejectingNumber) { pCurrentAction->nRejectingNumber = nRejectingNumber; }
    void SetActionInfo(const ScMyActionInfo& aInfo);
    void SetBigRange(const ScBigRange& aBigRange) { pCurrentAction->aBigRange = aBigRange; }
    void SetPreviousChange(const sal_uInt32 nPreviousAction, ScMyCellInfo* pCellInfo);
    void SetPosition(const sal_Int32 nPosition, const sal_Int32 nCount, const sal_Int32 nTable);
    void AddDependence(const sal_uInt32 nID) { pCurrentAction->aDependences.push_front(nID); }
    void AddDeleted(const sal_uInt32 nID);
    void AddDeleted(const sal_uInt32 nID, ScMyCellInfo* pCellInfo);
    void SetMultiSpanned(const sal_Int16 nMultiSpanned);
    void SetInsertionCutOff(const sal_uInt32 nID, const sal_Int32 nPosition);
    void AddMoveCutOff(const sal_uInt32 nID, const sal_Int32 nStartPosition, const sal_Int32 nEndPosition);
    void SetMoveRanges(const ScBigRange& aSourceRange, const ScBigRange& aTargetRange);
    void GetMultiSpannedRange();
    void AddGenerated(ScMyCellInfo* pCellInfo, const ScBigRange& aBigRange);

    void EndChangeAction();

    void SetDeletionDependences(ScMyDelAction* pAction, ScChangeActionDel* pDelAct);
    void SetMovementDependences(ScMyMoveAction* pAction, ScChangeActionMove* pMoveAct);
    void SetContentDependences(ScMyContentAction* pAction, ScChangeActionContent* pActContent);
    void SetDependences(ScMyBaseAction* pAction);

    void SetNewCell(ScMyContentAction* pAction);

    void CreateChangeTrack(ScDocument* pDoc);
};

#endif
<commit_msg>INTEGRATION: CWS rowlimit (1.9.324); FILE MERGED 2004/03/15 17:23:55 er 1.9.324.2: RESYNC: (1.9-1.10); FILE MERGED 2004/03/05 12:03:58 er 1.9.324.1: #i1967# type correctness<commit_after>/*************************************************************************
 *
 *  $RCSfile: XMLChangeTrackingImportHelper.hxx,v $
 *
 *  $Revision: 1.11 $
 *
 *  last change: $Author: obo $ $Date: 2004-06-04 11:08:18 $
 *
 *  The Contents of this file are made available subject to the terms of
 *  either of the following licenses
 *
 *         - GNU Lesser General Public License Version 2.1
 *         - Sun Industry Standards Source License Version 1.1
 *
 *  Sun Microsystems Inc., October, 2000
 *
 *  GNU Lesser General Public License Version 2.1
 *  =============================================
 *  Copyright 2000 by Sun Microsystems, Inc.
 *  901 San Antonio Road, Palo Alto, CA 94303, USA
 *
 *  This library is free software; you can redistribute it and/or
 *  modify it under the terms of the GNU Lesser General Public
 *  License version 2.1, as published by the Free Software Foundation.
 *
 *  This library is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 *  Lesser General Public License for more details.
 *
 *  You should have received a copy of the GNU Lesser General Public
 *  License along with this library; if not, write to the Free Software
 *  Foundation, Inc., 59 Temple Place, Suite 330, Boston,
 *  MA  02111-1307  USA
 *
 *
 *  Sun Industry Standards Source License Version 1.1
 *  =================================================
 *  The contents of this file are subject to the Sun Industry Standards
 *  Source License Version 1.1 (the "License"); You may not use this file
 *  except in compliance with the License. You may obtain a copy of the
 *  License at http://www.openoffice.org/license.html.
 *
 *  Software provided under this License is provided on an "AS IS" basis,
 *  WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING,
 *  WITHOUT LIMITATION, WARRANTIES THAT THE SOFTWARE IS FREE OF DEFECTS,
 *  MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE, OR NON-INFRINGING.
 *  See the License for the specific provisions governing your rights and
 *  obligations concerning the Software.
 *
 *  The Initial Developer of the Original Code is: Sun Microsystems, Inc.
 *
 *  Copyright: 2000 by Sun Microsystems, Inc.
 *
 *  All Rights Reserved.
 *
 *  Contributor(s): _______________________________________
 *
 *
 ************************************************************************/

#ifndef _SC_XMLCHANGETRACKINGIMPORTHELPER_HXX
#define _SC_XMLCHANGETRACKINGIMPORTHELPER_HXX

#ifndef SC_CHGTRACK_HXX
#include "chgtrack.hxx"
#endif

#ifndef __SGI_STL_LIST
#include <list>
#endif
#ifndef _SAL_TYPES_H_
#include <sal/types.h>
#endif
#ifndef _COM_SUN_STAR_UTIL_DATETIME_HPP_
#include <com/sun/star/util/DateTime.hpp>
#endif

class ScBaseCell;
class ScDocument;
class DateTime;

struct ScMyActionInfo
{
    rtl::OUString sUser;
    rtl::OUString sComment;
    com::sun::star::util::DateTime aDateTime;
};

struct ScMyCellInfo
{
    ScBaseCell*     pCell;
    rtl::OUString   sFormulaAddress;
    rtl::OUString   sFormula;
    String          sInputString;
    double          fValue;
    sal_Int32       nMatrixCols;
    sal_Int32       nMatrixRows;
    sal_uInt16      nType;
    sal_uInt8       nMatrixFlag;

    ScMyCellInfo();
    ScMyCellInfo(ScBaseCell* pCell, const rtl::OUString& sFormulaAddress, const rtl::OUString& sFormula, const rtl::OUString& sInputString,
                const double& fValue, const sal_uInt16 nType, const sal_uInt8 nMatrixFlag, const sal_Int32 nMatrixCols,
                const sal_Int32 nMatrixRows);
    ~ScMyCellInfo();

    ScBaseCell* CreateCell(ScDocument* pDoc);
};

struct ScMyDeleted
{
    sal_uInt32 nID;
    ScMyCellInfo* pCellInfo;

    ScMyDeleted();
    ~ScMyDeleted();
};

typedef std::list<ScMyDeleted*> ScMyDeletedList;

struct ScMyGenerated
{
    ScBigRange      aBigRange;
    sal_uInt32      nID;
    ScMyCellInfo*   pCellInfo;

    ScMyGenerated(ScMyCellInfo* pCellInfo, const ScBigRange& aBigRange);
    ~ScMyGenerated();
};

typedef std::list<ScMyGenerated*> ScMyGeneratedList;

struct ScMyInsertionCutOff
{
    sal_uInt32 nID;
    sal_Int32 nPosition;

    ScMyInsertionCutOff(const sal_uInt32 nTempID, const sal_Int32 nTempPosition) :
            nID(nTempID), nPosition(nTempPosition) {}
};

struct ScMyMoveCutOff
{
    sal_uInt32 nID;
    sal_Int32 nStartPosition;
    sal_Int32 nEndPosition;

    ScMyMoveCutOff(const sal_uInt32 nTempID, const sal_Int32 nStartPos, const sal_Int32 nEndPos) :
            nID(nTempID), nStartPosition(nStartPos), nEndPosition(nEndPos) {}
};

typedef std::list<ScMyMoveCutOff> ScMyMoveCutOffs;

struct ScMyMoveRanges
{
    ScBigRange aSourceRange;
    ScBigRange aTargetRange;

    ScMyMoveRanges(const ScBigRange& aSource, const ScBigRange aTarget) :
            aSourceRange(aSource), aTargetRange(aTarget) {}
};

typedef std::list<sal_uInt32> ScMyDependences;

struct ScMyBaseAction
{
    ScMyActionInfo aInfo;
    ScBigRange aBigRange;
    ScMyDependences aDependences;
    ScMyDeletedList aDeletedList;
    sal_uInt32 nActionNumber;
    sal_uInt32 nRejectingNumber;
    sal_uInt32 nPreviousAction;
    ScChangeActionType nActionType;
    ScChangeActionState nActionState;

    ScMyBaseAction(const ScChangeActionType nActionType);
    ~ScMyBaseAction();
};

struct ScMyInsAction : public ScMyBaseAction
{
    ScMyInsAction(const ScChangeActionType nActionType);
    ~ScMyInsAction();
};

struct ScMyDelAction : public ScMyBaseAction
{
    ScMyGeneratedList aGeneratedList;
    ScMyInsertionCutOff* pInsCutOff;
    ScMyMoveCutOffs aMoveCutOffs;
    sal_Int32 nD;

    ScMyDelAction(const ScChangeActionType nActionType);
    ~ScMyDelAction();
};

struct ScMyMoveAction : public ScMyBaseAction
{
    ScMyGeneratedList aGeneratedList;
    ScMyMoveRanges* pMoveRanges;

    ScMyMoveAction();
    ~ScMyMoveAction();
};

struct ScMyContentAction : public ScMyBaseAction
{
    ScMyCellInfo*   pCellInfo;

    ScMyContentAction();
    ~ScMyContentAction();
};

struct ScMyRejAction : public ScMyBaseAction
{
    ScMyRejAction();
    ~ScMyRejAction();
};

typedef std::list<ScMyBaseAction*> ScMyActions;

class ScChangeViewSettings;

class ScXMLChangeTrackingImportHelper
{
    StrCollection       aUsers;
    ScMyActions         aActions;
    com::sun::star::uno::Sequence<sal_Int8> aProtect;
    ScDocument*         pDoc;
    ScChangeTrack*      pTrack;
    ScMyBaseAction*     pCurrentAction;
    rtl::OUString       sIDPrefix;
    sal_uInt32          nPrefixLength;
    sal_Int16           nMultiSpanned;
    sal_Int16           nMultiSpannedSlaveCount;
    sal_Bool            bChangeTrack : 1;

private:
    void ConvertInfo(const ScMyActionInfo& aInfo, String& rUser, DateTime& aDateTime);
    ScChangeAction* CreateInsertAction(ScMyInsAction* pAction);
    ScChangeAction* CreateDeleteAction(ScMyDelAction* pAction);
    ScChangeAction* CreateMoveAction(ScMyMoveAction* pAction);
    ScChangeAction* CreateRejectionAction(ScMyRejAction* pAction);
    ScChangeAction* CreateContentAction(ScMyContentAction* pAction);

    void CreateGeneratedActions(ScMyGeneratedList& rList);

public:
    ScXMLChangeTrackingImportHelper();
    ~ScXMLChangeTrackingImportHelper();

    void SetChangeTrack(sal_Bool bValue) { bChangeTrack = bValue; }
    void SetProtection(const com::sun::star::uno::Sequence<sal_Int8>& rProtect) { aProtect = rProtect; }
    void StartChangeAction(const ScChangeActionType nActionType);

    sal_uInt32 GetIDFromString(const rtl::OUString& sID);

    void SetActionNumber(const sal_uInt32 nActionNumber) { pCurrentAction->nActionNumber = nActionNumber; }
    void SetActionState(const ScChangeActionState nActionState) { pCurrentAction->nActionState = nActionState; }
    void SetRejectingNumber(const sal_uInt32 nRejectingNumber) { pCurrentAction->nRejectingNumber = nRejectingNumber; }
    void SetActionInfo(const ScMyActionInfo& aInfo);
    void SetBigRange(const ScBigRange& aBigRange) { pCurrentAction->aBigRange = aBigRange; }
    void SetPreviousChange(const sal_uInt32 nPreviousAction, ScMyCellInfo* pCellInfo);
    void SetPosition(const sal_Int32 nPosition, const sal_Int32 nCount, const sal_Int32 nTable);
    void AddDependence(const sal_uInt32 nID) { pCurrentAction->aDependences.push_front(nID); }
    void AddDeleted(const sal_uInt32 nID);
    void AddDeleted(const sal_uInt32 nID, ScMyCellInfo* pCellInfo);
    void SetMultiSpanned(const sal_Int16 nMultiSpanned);
    void SetInsertionCutOff(const sal_uInt32 nID, const sal_Int32 nPosition);
    void AddMoveCutOff(const sal_uInt32 nID, const sal_Int32 nStartPosition, const sal_Int32 nEndPosition);
    void SetMoveRanges(const ScBigRange& aSourceRange, const ScBigRange& aTargetRange);
    void GetMultiSpannedRange();
    void AddGenerated(ScMyCellInfo* pCellInfo, const ScBigRange& aBigRange);

    void EndChangeAction();

    void SetDeletionDependences(ScMyDelAction* pAction, ScChangeActionDel* pDelAct);
    void SetMovementDependences(ScMyMoveAction* pAction, ScChangeActionMove* pMoveAct);
    void SetContentDependences(ScMyContentAction* pAction, ScChangeActionContent* pActContent);
    void SetDependences(ScMyBaseAction* pAction);

    void SetNewCell(ScMyContentAction* pAction);

    void CreateChangeTrack(ScDocument* pDoc);
};

#endif
<|endoftext|>


<commit_before>/******************************************************************************
 * Copyright 2018 The Apollo Authors. All Rights Reserved.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *****************************************************************************/

#include "modules/map/relative_map/navigation_lane.h"

#include <limits>

#include "modules/map/proto/map_lane.pb.h"

#include "modules/common/log.h"
#include "modules/common/math/math_utils.h"
#include "modules/common/math/vec2d.h"
#include "modules/common/util/util.h"
#include "modules/common/vehicle_state/vehicle_state_provider.h"
#include "modules/map/relative_map/common/relative_map_gflags.h"

namespace apollo {
namespace relative_map {

using apollo::common::VehicleStateProvider;
using apollo::common::math::Vec2d;
using apollo::common::util::DistanceXY;
using apollo::hdmap::Lane;
using apollo::common::util::operator+;
using apollo::perception::PerceptionObstacles;

NavigationLane::NavigationLane(const NavigationLaneConfig& config)
    : config_(config) {}

void NavigationLane::SetConfig(const NavigationLaneConfig& config) {
  config_ = config;
}

bool NavigationLane::GeneratePath() {
  // update adc_state_ from VehicleStateProvider
  adc_state_ = VehicleStateProvider::instance()->vehicle_state();

  navigation_path_.Clear();
  auto* path = navigation_path_.mutable_path();
  const auto& lane_marker = perception_obstacles_.lane_marker();

  if (std::fmin(lane_marker.left_lane_marker().quality(),
                lane_marker.right_lane_marker().quality()) >
      config_.min_lane_marker_quality()) {
    ConvertLaneMarkerToPath(perception_obstacles_.lane_marker(), path);
  } else if (navigation_info_.navigation_path_size() > 0) {
    ConvertNavigationLineToPath(path);
  } else {
    AERROR << "Navigation Path is empty because neither lane markers nor "
              "navigation line are available.";
  }

  return true;
}

double NavigationLane::EvaluateCubicPolynomial(const double c0, const double c1,
                                               const double c2, const double c3,
                                               const double z) const {
  return ((c3 * z + c2) * z + c1) * z + c0;
}

void NavigationLane::ConvertNavigationLineToPath(common::Path* path) {
  CHECK_NOTNULL(path);
  if (navigation_info_.navigation_path_size() == 0 ||
      !navigation_info_.navigation_path(0).has_path() ||
      navigation_info_.navigation_path(0).path().path_point_size() == 0) {
    // path is empty
    return;
  }
  path->set_name("Path from navigation.");
  UpdateProjectionIndex();

  // TODO(All): support multiple navigation path
  // currently, only 1 navigation path is supported
  const auto& navigation_path = navigation_info_.navigation_path(0).path();
  int curr_project_index = last_project_index_;

  // offset between the current vehicle state and navigation line
  const double dx = -navigation_path.path_point(curr_project_index).x();
  const double dy = -navigation_path.path_point(curr_project_index).y();
  for (int i = curr_project_index; i < navigation_path.path_point_size(); ++i) {
    auto* point = path->add_path_point();
    point->CopyFrom(navigation_path.path_point(i));

    // shift to (0, 0)
    double emu_x = point->x() + dx;
    double emu_y = point->y() + dy;

    double flu_x = 0.0;
    double flu_y = 0.0;
    common::math::RotateAxis(adc_state_.heading(), emu_x, emu_y, &flu_x,
                             &flu_y);

    point->set_x(flu_x);
    point->set_y(flu_y);
    const double accumulated_s =
        navigation_path.path_point(i).s() -
        navigation_path.path_point(curr_project_index).s();
    point->set_s(accumulated_s);

    if (accumulated_s > FLAGS_max_len_from_navigation_line) {
      break;
    }
  }

  // set left/right width invalid as no width info from navigation line
  left_width_ = -1.0;
  right_width_ = -1.0;
}

// project adc_state_ onto path
void NavigationLane::UpdateProjectionIndex() {
  // TODO(All): support multiple navigation path
  // currently, only 1 navigation path is supported
  const auto& path = navigation_info_.navigation_path(0).path();
  int index = 0;
  double min_d = std::numeric_limits<double>::max();
  for (int i = last_project_index_; i + 1 < path.path_point_size(); ++i) {
    const double d = DistanceXY(adc_state_, path.path_point(i));
    if (d < min_d) {
      min_d = d;
      index = i;
    }
    const double kMaxDistance = 50.0;
    if (d > kMaxDistance) {
      break;
    }
  }
  last_project_index_ = index;
}

void NavigationLane::ConvertLaneMarkerToPath(
    const perception::LaneMarkers& lane_marker, common::Path* path) {
  CHECK_NOTNULL(path);

  path->set_name("Path from lane markers.");
  const auto& left_lane = lane_marker.left_lane_marker();
  const auto& right_lane = lane_marker.right_lane_marker();

  const double unit_z = 1.0;
  if (left_lane.view_range() > right_lane.view_range()) {
    const double x_l_0 = EvaluateCubicPolynomial(
        left_lane.c0_position(), left_lane.c1_heading_angle(),
        left_lane.c2_curvature(), left_lane.c3_curvature_derivative(), 0.0);

    double accumulated_s = 0.0;
    for (double z = 0; z <= left_lane.view_range(); z += unit_z) {
      const double x_l = EvaluateCubicPolynomial(
          left_lane.c0_position(), left_lane.c1_heading_angle(),
          left_lane.c2_curvature(), left_lane.c3_curvature_derivative(), z);

      if (left_width_ < 0.0) {
        left_width_ = std::fabs(x_l);
      }
      if (right_width_ < 0.0) {
        right_width_ = left_width_;
      }

      double x1 = z;
      // TODO(All): use more precise method to shift y
      double y1 = std::fabs(x_l) - std::fabs(x_l_0);

      auto* point = path->add_path_point();
      point->set_x(x1);
      point->set_y(y1);
      point->set_s(accumulated_s);

      if (path->path_point_size() > 1) {
        auto& pre_point = path->path_point(path->path_point_size() - 2);
        accumulated_s += std::hypot(x1 - pre_point.x(), y1 - pre_point.y());
      }
    }
  } else {
    const double x_r_0 = EvaluateCubicPolynomial(
        right_lane.c0_position(), right_lane.c1_heading_angle(),
        right_lane.c2_curvature(), right_lane.c3_curvature_derivative(), 0.0);
    double accumulated_s = 0.0;
    for (double z = 0; z <= right_lane.view_range(); z += unit_z) {
      const double x_r = EvaluateCubicPolynomial(
          right_lane.c0_position(), right_lane.c1_heading_angle(),
          right_lane.c2_curvature(), right_lane.c3_curvature_derivative(), z);

      if (right_width_ < 0.0) {
        right_width_ = left_width_;
      }
      if (left_width_ < 0.0) {
        left_width_ = right_width_;
      }

      double x1 = z;
      // TODO(All): use more precise method to shift y
      double y1 = -std::fabs(x_r) + std::fabs(x_r_0);

      auto* point = path->add_path_point();
      point->set_x(x1);
      point->set_y(y1);
      point->set_s(accumulated_s);

      if (path->path_point_size() > 1) {
        auto& pre_point = path->path_point(path->path_point_size() - 2);
        accumulated_s += std::hypot(x1 - pre_point.x(), y1 - pre_point.y());
      }
    }
  }
}

bool NavigationLane::CreateMap(const MapGenerationParam& map_config,
                               MapMsg* map_msg) const {
  auto* navigation_info = map_msg->mutable_navigation_path();
  auto* hdmap = map_msg->mutable_hdmap();
  auto* lane_marker = map_msg->mutable_lane_marker();

  lane_marker->CopyFrom(perception_obstacles_.lane_marker());

  const auto& path = navigation_path_.path();
  if (path.path_point_size() < 2) {
    AERROR << "The path length is invalid";
    return false;
  }
  auto* lane = hdmap->add_lane();
  lane->mutable_id()->set_id(std::to_string(navigation_path_.path_priority()) +
                             "_" + path.name());
  (*navigation_info)[lane->id().id()] = navigation_path_;
  // lane types
  lane->set_type(Lane::CITY_DRIVING);
  lane->set_turn(Lane::NO_TURN);

  // speed limit
  lane->set_speed_limit(map_config.default_speed_limit());

  // center line
  auto* curve_segment = lane->mutable_central_curve()->add_segment();
  curve_segment->set_heading(path.path_point(0).theta());
  auto* line_segment = curve_segment->mutable_line_segment();
  // left boundary
  auto* left_boundary = lane->mutable_left_boundary();
  auto* left_boundary_type = left_boundary->add_boundary_type();
  left_boundary->set_virtual_(false);
  left_boundary_type->set_s(0.0);
  left_boundary_type->add_types(
      perception_obstacles_.lane_marker().left_lane_marker().lane_type());
  auto* left_segment =
      left_boundary->mutable_curve()->add_segment()->mutable_line_segment();
  // right boundary
  auto* right_boundary = lane->mutable_right_boundary();
  auto* right_boundary_type = right_boundary->add_boundary_type();
  right_boundary->set_virtual_(false);
  right_boundary_type->set_s(0.0);
  right_boundary_type->add_types(
      perception_obstacles_.lane_marker().right_lane_marker().lane_type());
  auto* right_segment =
      right_boundary->mutable_curve()->add_segment()->mutable_line_segment();
  const double lane_left_width =
      left_width_ > 0 ? left_width_ : map_config.default_left_width();
  const double lane_right_width =
      right_width_ > 0 ? right_width_ : map_config.default_right_width();
  for (const auto& path_point : path.path_point()) {
    auto* point = line_segment->add_point();
    point->set_x(path_point.x());
    point->set_y(path_point.y());
    point->set_z(path_point.z());
    auto* left_sample = lane->add_left_sample();
    left_sample->set_s(path_point.s());
    left_sample->set_width(lane_left_width);
    left_segment->add_point()->CopyFrom(
        *point +
        lane_left_width * Vec2d::CreateUnitVec2d(path_point.theta() + M_PI_2));
    auto* right_sample = lane->add_right_sample();
    right_sample->set_s(path_point.s());
    right_sample->set_width(lane_right_width);
    right_segment->add_point()->CopyFrom(
        *point +
        lane_right_width * Vec2d::CreateUnitVec2d(path_point.theta() - M_PI_2));
  }

  return true;
}

}  // namespace relative_map
}  // namespace apollo
<commit_msg>Navigation: do not move navigation line to ego vehicle, prefer using navigation line than lane markers.<commit_after>/******************************************************************************
 * Copyright 2018 The Apollo Authors. All Rights Reserved.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *****************************************************************************/

#include "modules/map/relative_map/navigation_lane.h"

#include <limits>

#include "modules/map/proto/map_lane.pb.h"

#include "modules/common/log.h"
#include "modules/common/math/math_utils.h"
#include "modules/common/math/vec2d.h"
#include "modules/common/util/util.h"
#include "modules/common/vehicle_state/vehicle_state_provider.h"
#include "modules/map/relative_map/common/relative_map_gflags.h"

namespace apollo {
namespace relative_map {

using apollo::common::VehicleStateProvider;
using apollo::common::math::Vec2d;
using apollo::common::util::DistanceXY;
using apollo::hdmap::Lane;
using apollo::common::util::operator+;
using apollo::perception::PerceptionObstacles;

NavigationLane::NavigationLane(const NavigationLaneConfig& config)
    : config_(config) {}

void NavigationLane::SetConfig(const NavigationLaneConfig& config) {
  config_ = config;
}

bool NavigationLane::GeneratePath() {
  // update adc_state_ from VehicleStateProvider
  adc_state_ = VehicleStateProvider::instance()->vehicle_state();

  navigation_path_.Clear();
  auto* path = navigation_path_.mutable_path();
  const auto& lane_marker = perception_obstacles_.lane_marker();

  // priority: navigation line > perception lane marker
  if (navigation_info_.navigation_path_size() > 0) {
    ConvertNavigationLineToPath(path);
  } else if (std::fmin(lane_marker.left_lane_marker().quality(),
                       lane_marker.right_lane_marker().quality()) >
             config_.min_lane_marker_quality()) {
    ConvertLaneMarkerToPath(perception_obstacles_.lane_marker(), path);
  } else {
    AERROR << "Navigation Path is empty because neither lane markers nor "
              "navigation line are available.";
  }

  return true;
}

double NavigationLane::EvaluateCubicPolynomial(const double c0, const double c1,
                                               const double c2, const double c3,
                                               const double z) const {
  return ((c3 * z + c2) * z + c1) * z + c0;
}

void NavigationLane::ConvertNavigationLineToPath(common::Path* path) {
  CHECK_NOTNULL(path);
  if (navigation_info_.navigation_path_size() == 0 ||
      !navigation_info_.navigation_path(0).has_path() ||
      navigation_info_.navigation_path(0).path().path_point_size() == 0) {
    // path is empty
    return;
  }
  path->set_name("Path from navigation.");
  UpdateProjectionIndex();

  // TODO(All): support multiple navigation path
  // currently, only 1 navigation path is supported
  const auto& navigation_path = navigation_info_.navigation_path(0).path();
  int curr_project_index = last_project_index_;

  // offset between the current vehicle state and navigation line
  const double dx = -adc_state_.x();
  const double dy = -adc_state_.y();
  for (int i = curr_project_index; i < navigation_path.path_point_size(); ++i) {
    auto* point = path->add_path_point();
    point->CopyFrom(navigation_path.path_point(i));

    // shift to (0, 0)
    double emu_x = point->x() + dx;
    double emu_y = point->y() + dy;

    double flu_x = 0.0;
    double flu_y = 0.0;
    common::math::RotateAxis(adc_state_.heading(), emu_x, emu_y, &flu_x,
                             &flu_y);

    point->set_x(flu_x);
    point->set_y(flu_y);
    const double accumulated_s =
        navigation_path.path_point(i).s() -
        navigation_path.path_point(curr_project_index).s();
    point->set_s(accumulated_s);

    if (accumulated_s > FLAGS_max_len_from_navigation_line) {
      break;
    }
  }

  // set left/right width invalid as no width info from navigation line
  left_width_ = -1.0;
  right_width_ = -1.0;
}

// project adc_state_ onto path
void NavigationLane::UpdateProjectionIndex() {
  // TODO(All): support multiple navigation path
  // currently, only 1 navigation path is supported
  const auto& path = navigation_info_.navigation_path(0).path();
  int index = 0;
  double min_d = std::numeric_limits<double>::max();
  for (int i = last_project_index_; i + 1 < path.path_point_size(); ++i) {
    const double d = DistanceXY(adc_state_, path.path_point(i));
    if (d < min_d) {
      min_d = d;
      index = i;
    }
    const double kMaxDistance = 50.0;
    if (d > kMaxDistance) {
      break;
    }
  }
  last_project_index_ = index;
}

void NavigationLane::ConvertLaneMarkerToPath(
    const perception::LaneMarkers& lane_marker, common::Path* path) {
  CHECK_NOTNULL(path);

  path->set_name("Path from lane markers.");
  const auto& left_lane = lane_marker.left_lane_marker();
  const auto& right_lane = lane_marker.right_lane_marker();

  const double unit_z = 1.0;
  if (left_lane.view_range() > right_lane.view_range()) {
    const double x_l_0 = EvaluateCubicPolynomial(
        left_lane.c0_position(), left_lane.c1_heading_angle(),
        left_lane.c2_curvature(), left_lane.c3_curvature_derivative(), 0.0);

    double accumulated_s = 0.0;
    for (double z = 0; z <= left_lane.view_range(); z += unit_z) {
      const double x_l = EvaluateCubicPolynomial(
          left_lane.c0_position(), left_lane.c1_heading_angle(),
          left_lane.c2_curvature(), left_lane.c3_curvature_derivative(), z);

      if (left_width_ < 0.0) {
        left_width_ = std::fabs(x_l);
      }
      if (right_width_ < 0.0) {
        right_width_ = left_width_;
      }

      double x1 = z;
      // TODO(All): use more precise method to shift y
      double y1 = std::fabs(x_l) - std::fabs(x_l_0);

      auto* point = path->add_path_point();
      point->set_x(x1);
      point->set_y(y1);
      point->set_s(accumulated_s);

      if (path->path_point_size() > 1) {
        auto& pre_point = path->path_point(path->path_point_size() - 2);
        accumulated_s += std::hypot(x1 - pre_point.x(), y1 - pre_point.y());
      }
    }
  } else {
    const double x_r_0 = EvaluateCubicPolynomial(
        right_lane.c0_position(), right_lane.c1_heading_angle(),
        right_lane.c2_curvature(), right_lane.c3_curvature_derivative(), 0.0);
    double accumulated_s = 0.0;
    for (double z = 0; z <= right_lane.view_range(); z += unit_z) {
      const double x_r = EvaluateCubicPolynomial(
          right_lane.c0_position(), right_lane.c1_heading_angle(),
          right_lane.c2_curvature(), right_lane.c3_curvature_derivative(), z);

      if (right_width_ < 0.0) {
        right_width_ = left_width_;
      }
      if (left_width_ < 0.0) {
        left_width_ = right_width_;
      }

      double x1 = z;
      // TODO(All): use more precise method to shift y
      double y1 = -std::fabs(x_r) + std::fabs(x_r_0);

      auto* point = path->add_path_point();
      point->set_x(x1);
      point->set_y(y1);
      point->set_s(accumulated_s);

      if (path->path_point_size() > 1) {
        auto& pre_point = path->path_point(path->path_point_size() - 2);
        accumulated_s += std::hypot(x1 - pre_point.x(), y1 - pre_point.y());
      }
    }
  }
}

bool NavigationLane::CreateMap(const MapGenerationParam& map_config,
                               MapMsg* map_msg) const {
  auto* navigation_info = map_msg->mutable_navigation_path();
  auto* hdmap = map_msg->mutable_hdmap();
  auto* lane_marker = map_msg->mutable_lane_marker();

  lane_marker->CopyFrom(perception_obstacles_.lane_marker());

  const auto& path = navigation_path_.path();
  if (path.path_point_size() < 2) {
    AERROR << "The path length is invalid";
    return false;
  }
  auto* lane = hdmap->add_lane();
  lane->mutable_id()->set_id(std::to_string(navigation_path_.path_priority()) +
                             "_" + path.name());
  (*navigation_info)[lane->id().id()] = navigation_path_;
  // lane types
  lane->set_type(Lane::CITY_DRIVING);
  lane->set_turn(Lane::NO_TURN);

  // speed limit
  lane->set_speed_limit(map_config.default_speed_limit());

  // center line
  auto* curve_segment = lane->mutable_central_curve()->add_segment();
  curve_segment->set_heading(path.path_point(0).theta());
  auto* line_segment = curve_segment->mutable_line_segment();
  // left boundary
  auto* left_boundary = lane->mutable_left_boundary();
  auto* left_boundary_type = left_boundary->add_boundary_type();
  left_boundary->set_virtual_(false);
  left_boundary_type->set_s(0.0);
  left_boundary_type->add_types(
      perception_obstacles_.lane_marker().left_lane_marker().lane_type());
  auto* left_segment =
      left_boundary->mutable_curve()->add_segment()->mutable_line_segment();
  // right boundary
  auto* right_boundary = lane->mutable_right_boundary();
  auto* right_boundary_type = right_boundary->add_boundary_type();
  right_boundary->set_virtual_(false);
  right_boundary_type->set_s(0.0);
  right_boundary_type->add_types(
      perception_obstacles_.lane_marker().right_lane_marker().lane_type());
  auto* right_segment =
      right_boundary->mutable_curve()->add_segment()->mutable_line_segment();
  const double lane_left_width =
      left_width_ > 0 ? left_width_ : map_config.default_left_width();
  const double lane_right_width =
      right_width_ > 0 ? right_width_ : map_config.default_right_width();
  for (const auto& path_point : path.path_point()) {
    auto* point = line_segment->add_point();
    point->set_x(path_point.x());
    point->set_y(path_point.y());
    point->set_z(path_point.z());
    auto* left_sample = lane->add_left_sample();
    left_sample->set_s(path_point.s());
    left_sample->set_width(lane_left_width);
    left_segment->add_point()->CopyFrom(
        *point +
        lane_left_width * Vec2d::CreateUnitVec2d(path_point.theta() + M_PI_2));
    auto* right_sample = lane->add_right_sample();
    right_sample->set_s(path_point.s());
    right_sample->set_width(lane_right_width);
    right_segment->add_point()->CopyFrom(
        *point +
        lane_right_width * Vec2d::CreateUnitVec2d(path_point.theta() - M_PI_2));
  }

  return true;
}

}  // namespace relative_map
}  // namespace apollo
<|endoftext|>


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

#include "modules/skottie/src/effects/Effects.h"

#include "include/core/SkCanvas.h"
#include "include/core/SkPictureRecorder.h"
#include "include/effects/SkRuntimeEffect.h"
#include "modules/skottie/src/Adapter.h"
#include "modules/skottie/src/SkottieValue.h"
#include "modules/sksg/include/SkSGPaint.h"
#include "modules/sksg/include/SkSGRenderNode.h"
#include "src/utils/SkJSON.h"

namespace skottie::internal {

#ifdef SK_ENABLE_SKSL

namespace {

static constexpr char gBulgeDisplacementSkSL[] =
    "uniform shader u_layer;"

    "uniform float2 u_center;"
    "uniform float2 u_radius;"
    "uniform float u_h;"
    "uniform float u_r;"
    "uniform float u_asinInverseR;"
    "uniform float u_rcpR;"
    "uniform float u_rcpAsinInvR;"
    "uniform float u_selector;"

    // AE's bulge effect appears to be a combination of spherical displacement and
    // exponential displacement along the radius.
    // To simplify the math, we pre scale/translate such that the ellipse becomes a
    // circle with radius == 1, centered on origin.
    "float2 displace_sph(float2 v) {"
        "float arc_ratio = asin(length(v)*u_rcpR)*u_rcpAsinInvR;"
        "return normalize(v)*arc_ratio - v;"
    "}"

    "float2 displace_exp(float2 v) {"
        "return v*pow(dot(v,v),u_h) - v;"
    "}"

    "half2 displace(float2 v) {"
        "float t = dot(v, v);"
        "if (t >= 1) {"
            "return v;"
        "}"
        "float2 d = displace_sph(v) + displace_exp(v);"
        "return v + (d * u_selector);"
    "}"

    "half4 main(float2 xy) {"
        "xy = displace(xy);"
        "xy = xy*u_radius + u_center;"
        "return u_layer.eval(xy);"
    "}";

static sk_sp<SkRuntimeEffect> bulge_effect() {
    static const SkRuntimeEffect* effect =
        SkRuntimeEffect::MakeForShader(SkString(gBulgeDisplacementSkSL), {}).effect.release();
    SkASSERT(effect);

    return sk_ref_sp(effect);
}

class BulgeNode final : public sksg::CustomRenderNode {
public:
    explicit BulgeNode(sk_sp<RenderNode> child, const SkSize& child_size)
        : INHERITED({std::move(child)})
        , fChildSize(child_size) {}

    SG_ATTRIBUTE(Center  , SkPoint   , fCenter)
    SG_ATTRIBUTE(Radius  , SkVector  , fRadius)
    SG_ATTRIBUTE(Height  , float     , fHeight)

private:
    sk_sp<SkShader> contentShader() {
        if (!fContentShader || this->hasChildrenInval()) {
            const auto& child = this->children()[0];
            child->revalidate(nullptr, SkMatrix::I());

            SkPictureRecorder recorder;
            child->render(recorder.beginRecording(SkRect::MakeSize(fChildSize)));

            fContentShader = recorder.finishRecordingAsPicture()
                    ->makeShader(SkTileMode::kRepeat, SkTileMode::kRepeat, SkFilterMode::kLinear,
                                 nullptr, nullptr);
        }

        return fContentShader;
    }

    sk_sp<SkShader> buildEffectShader() {
        if (fHeight == 0) {
            return nullptr;
        }

        SkRuntimeShaderBuilder builder(bulge_effect());
        float adjHeight = std::abs(fHeight)/4;
        float r = (1 + adjHeight)/2/sqrt(adjHeight);
        float h = std::pow(adjHeight, 3)*1.3;
        builder.uniform("u_center")       = fCenter;
        builder.uniform("u_radius")       = fRadius;
        builder.uniform("u_h")            = h;
        builder.uniform("u_r")            = r;
        builder.uniform("u_asinInverseR") = std::asin(1/r);
        builder.uniform("u_rcpR")            = 1.0f/r;
        builder.uniform("u_rcpAsinInvR") = 1.0f/std::asin(1/r);
        builder.uniform("u_selector")     = (fHeight > 0 ? 1.0f : -1.0f);

        builder.child("u_layer") = this->contentShader();

        const auto lm = SkMatrix::Translate(fCenter.x(), fCenter.y())
                      * SkMatrix::Scale(fRadius.x(), fRadius.y());
        return builder.makeShader(&lm);
    }

    SkRect onRevalidate(sksg::InvalidationController* ic, const SkMatrix& ctm) override {
        const auto& child = this->children()[0];
        fEffectShader = buildEffectShader();
        return child->revalidate(ic, ctm);
    }

    void onRender(SkCanvas* canvas, const RenderContext* ctx) const override {
        if (fHeight == 0) {
            this->children()[0]->render(canvas, ctx);
            return;
        }
        const auto& bounds = this->bounds();
        const auto local_ctx = ScopedRenderContext(canvas, ctx)
                .setIsolation(bounds, canvas->getTotalMatrix(), true);

        canvas->saveLayer(&bounds, nullptr);

        SkPaint effect_paint;
        effect_paint.setShader(fEffectShader);
        effect_paint.setBlendMode(SkBlendMode::kSrcOver);

        canvas->drawPaint(effect_paint);
    }

    const RenderNode* onNodeAt(const SkPoint&) const override { return nullptr; } // no hit-testing

    sk_sp<SkShader> fEffectShader;
    sk_sp<SkShader> fContentShader;
    const SkSize fChildSize;

    SkPoint  fCenter = {0,0};
    SkVector fRadius = {0,0};
    float   fHeight = 0;

    using INHERITED = sksg::CustomRenderNode;
};

class BulgeEffectAdapter final : public DiscardableAdapterBase<BulgeEffectAdapter,
                                                             BulgeNode> {
public:
    BulgeEffectAdapter(const skjson::ArrayValue& jprops,
                      const AnimationBuilder& abuilder,
                      sk_sp<BulgeNode> node)
        : INHERITED(std::move(node))
    {
        enum : size_t {
            kHorizontalRadius_Index = 0,
            kVerticalRadius_Index = 1,
            kBulgeCenter_Index = 2,
            kBulgeHeight_Index = 3,
            // kTaper_Index = 4,
            // kAA_Index = 5,
            // kPinning_Index = 6,
        };
        EffectBinder(jprops, abuilder, this).bind(kHorizontalRadius_Index, fHorizontalRadius)
                                            .bind(kVerticalRadius_Index, fVerticalRadius)
                                            .bind(kBulgeCenter_Index, fCenter)
                                            .bind(kBulgeHeight_Index, fBulgeHeight);
    }

private:
    void onSync() override {
        // pre-shader math
        auto n = this->node();
        n->setCenter({fCenter.x, fCenter.y});
        n->setRadius({fHorizontalRadius, fVerticalRadius});
        n->setHeight(fBulgeHeight);
    }

    Vec2Value fCenter;
    ScalarValue fHorizontalRadius,
                fVerticalRadius,
                fBulgeHeight;
    using INHERITED = DiscardableAdapterBase<BulgeEffectAdapter, BulgeNode>;
};

} // namespace

#endif  // SK_ENABLE_SKSL

sk_sp<sksg::RenderNode> EffectBuilder::attachBulgeEffect(const skjson::ArrayValue& jprops,
                                                             sk_sp<sksg::RenderNode> layer) const {
#ifdef SK_ENABLE_SKSL
    auto shaderNode = sk_make_sp<BulgeNode>(std::move(layer), fLayerSize);
    return fBuilder->attachDiscardableAdapter<BulgeEffectAdapter>(jprops, *fBuilder, std::move(shaderNode));
#else
    return layer;
#endif
}

} // namespace skottie::internal
<commit_msg>Remove unused uniforms from BulgeEffect.<commit_after>/*
 * Copyright 2021 Google Inc.
 *
 * Use of this source code is governed by a BSD-style license that can be
 * found in the LICENSE file.
 */

#include "modules/skottie/src/effects/Effects.h"

#include "include/core/SkCanvas.h"
#include "include/core/SkPictureRecorder.h"
#include "include/effects/SkRuntimeEffect.h"
#include "modules/skottie/src/Adapter.h"
#include "modules/skottie/src/SkottieValue.h"
#include "modules/sksg/include/SkSGPaint.h"
#include "modules/sksg/include/SkSGRenderNode.h"
#include "src/utils/SkJSON.h"

namespace skottie::internal {

#ifdef SK_ENABLE_SKSL

namespace {

static constexpr char gBulgeDisplacementSkSL[] =
    "uniform shader u_layer;"

    "uniform float2 u_center;"
    "uniform float2 u_radius;"
    "uniform float u_h;"
    "uniform float u_rcpR;"
    "uniform float u_rcpAsinInvR;"
    "uniform float u_selector;"

    // AE's bulge effect appears to be a combination of spherical displacement and
    // exponential displacement along the radius.
    // To simplify the math, we pre scale/translate such that the ellipse becomes a
    // circle with radius == 1, centered on origin.
    "float2 displace_sph(float2 v) {"
        "float arc_ratio = asin(length(v)*u_rcpR)*u_rcpAsinInvR;"
        "return normalize(v)*arc_ratio - v;"
    "}"

    "float2 displace_exp(float2 v) {"
        "return v*pow(dot(v,v),u_h) - v;"
    "}"

    "half2 displace(float2 v) {"
        "float t = dot(v, v);"
        "if (t >= 1) {"
            "return v;"
        "}"
        "float2 d = displace_sph(v) + displace_exp(v);"
        "return v + (d * u_selector);"
    "}"

    "half4 main(float2 xy) {"
        "xy = displace(xy);"
        "xy = xy*u_radius + u_center;"
        "return u_layer.eval(xy);"
    "}";

static sk_sp<SkRuntimeEffect> bulge_effect() {
    static const SkRuntimeEffect* effect =
        SkRuntimeEffect::MakeForShader(SkString(gBulgeDisplacementSkSL), {}).effect.release();
    SkASSERT(effect);

    return sk_ref_sp(effect);
}

class BulgeNode final : public sksg::CustomRenderNode {
public:
    explicit BulgeNode(sk_sp<RenderNode> child, const SkSize& child_size)
        : INHERITED({std::move(child)})
        , fChildSize(child_size) {}

    SG_ATTRIBUTE(Center  , SkPoint   , fCenter)
    SG_ATTRIBUTE(Radius  , SkVector  , fRadius)
    SG_ATTRIBUTE(Height  , float     , fHeight)

private:
    sk_sp<SkShader> contentShader() {
        if (!fContentShader || this->hasChildrenInval()) {
            const auto& child = this->children()[0];
            child->revalidate(nullptr, SkMatrix::I());

            SkPictureRecorder recorder;
            child->render(recorder.beginRecording(SkRect::MakeSize(fChildSize)));

            fContentShader = recorder.finishRecordingAsPicture()
                    ->makeShader(SkTileMode::kRepeat, SkTileMode::kRepeat, SkFilterMode::kLinear,
                                 nullptr, nullptr);
        }

        return fContentShader;
    }

    sk_sp<SkShader> buildEffectShader() {
        if (fHeight == 0) {
            return nullptr;
        }

        SkRuntimeShaderBuilder builder(bulge_effect());
        float adjHeight = std::abs(fHeight)/4;
        float r = (1 + adjHeight)/2/sqrt(adjHeight);
        float h = std::pow(adjHeight, 3)*1.3;
        builder.uniform("u_center")       = fCenter;
        builder.uniform("u_radius")       = fRadius;
        builder.uniform("u_h")            = h;
        builder.uniform("u_rcpR")         = 1.0f/r;
        builder.uniform("u_rcpAsinInvR")  = 1.0f/std::asin(1/r);
        builder.uniform("u_selector")     = (fHeight > 0 ? 1.0f : -1.0f);

        builder.child("u_layer") = this->contentShader();

        const auto lm = SkMatrix::Translate(fCenter.x(), fCenter.y())
                      * SkMatrix::Scale(fRadius.x(), fRadius.y());
        return builder.makeShader(&lm);
    }

    SkRect onRevalidate(sksg::InvalidationController* ic, const SkMatrix& ctm) override {
        const auto& child = this->children()[0];
        fEffectShader = buildEffectShader();
        return child->revalidate(ic, ctm);
    }

    void onRender(SkCanvas* canvas, const RenderContext* ctx) const override {
        if (fHeight == 0) {
            this->children()[0]->render(canvas, ctx);
            return;
        }
        const auto& bounds = this->bounds();
        const auto local_ctx = ScopedRenderContext(canvas, ctx)
                .setIsolation(bounds, canvas->getTotalMatrix(), true);

        canvas->saveLayer(&bounds, nullptr);

        SkPaint effect_paint;
        effect_paint.setShader(fEffectShader);
        effect_paint.setBlendMode(SkBlendMode::kSrcOver);

        canvas->drawPaint(effect_paint);
    }

    const RenderNode* onNodeAt(const SkPoint&) const override { return nullptr; } // no hit-testing

    sk_sp<SkShader> fEffectShader;
    sk_sp<SkShader> fContentShader;
    const SkSize fChildSize;

    SkPoint  fCenter = {0,0};
    SkVector fRadius = {0,0};
    float   fHeight = 0;

    using INHERITED = sksg::CustomRenderNode;
};

class BulgeEffectAdapter final : public DiscardableAdapterBase<BulgeEffectAdapter,
                                                             BulgeNode> {
public:
    BulgeEffectAdapter(const skjson::ArrayValue& jprops,
                      const AnimationBuilder& abuilder,
                      sk_sp<BulgeNode> node)
        : INHERITED(std::move(node))
    {
        enum : size_t {
            kHorizontalRadius_Index = 0,
            kVerticalRadius_Index = 1,
            kBulgeCenter_Index = 2,
            kBulgeHeight_Index = 3,
            // kTaper_Index = 4,
            // kAA_Index = 5,
            // kPinning_Index = 6,
        };
        EffectBinder(jprops, abuilder, this).bind(kHorizontalRadius_Index, fHorizontalRadius)
                                            .bind(kVerticalRadius_Index, fVerticalRadius)
                                            .bind(kBulgeCenter_Index, fCenter)
                                            .bind(kBulgeHeight_Index, fBulgeHeight);
    }

private:
    void onSync() override {
        // pre-shader math
        auto n = this->node();
        n->setCenter({fCenter.x, fCenter.y});
        n->setRadius({fHorizontalRadius, fVerticalRadius});
        n->setHeight(fBulgeHeight);
    }

    Vec2Value fCenter;
    ScalarValue fHorizontalRadius,
                fVerticalRadius,
                fBulgeHeight;
    using INHERITED = DiscardableAdapterBase<BulgeEffectAdapter, BulgeNode>;
};

} // namespace

#endif  // SK_ENABLE_SKSL

sk_sp<sksg::RenderNode> EffectBuilder::attachBulgeEffect(const skjson::ArrayValue& jprops,
                                                             sk_sp<sksg::RenderNode> layer) const {
#ifdef SK_ENABLE_SKSL
    auto shaderNode = sk_make_sp<BulgeNode>(std::move(layer), fLayerSize);
    return fBuilder->attachDiscardableAdapter<BulgeEffectAdapter>(jprops, *fBuilder, std::move(shaderNode));
#else
    return layer;
#endif
}

} // namespace skottie::internal
<|endoftext|>