<commit_before>/*
 * Copyright(c) Sophist Solutions, Inc. 1990-2014.  All rights reserved
 */
//  TEST    Foundation::Execution::ThreadSafetyBuiltinObject
#include    "Stroika/Foundation/StroikaPreComp.h"

#include    <iostream>
#include    <mutex>

#include    "Stroika/Foundation/Execution/BlockingQueue.h"
#include    "Stroika/Foundation/Execution/Finally.h"
#include    "Stroika/Foundation/Execution/Lockable.h"
#include    "Stroika/Foundation/Execution/Sleep.h"
#include    "Stroika/Foundation/Execution/SpinLock.h"
#include    "Stroika/Foundation/Execution/Thread.h"
#include    "Stroika/Foundation/Execution/ThreadPool.h"
#include    "Stroika/Foundation/Execution/WaitableEvent.h"
#include    "Stroika/Foundation/Execution/TimeOutException.h"

#include    "../TestHarness/TestHarness.h"

using   namespace   Stroika::Foundation;

using   Execution::BlockingQueue;
using   Execution::Lockable;
using   Execution::Thread;
using   Execution::Finally;
using   Execution::SpinLock;
using   Execution::ThreadPool;
using   Execution::WaitableEvent;

#include    "Stroika/Foundation/Containers/Sequence.h"
using   Containers::Sequence;

namespace   {
    void    RegressionTest1_ ()
    {
        Debug::TraceContextBumper traceCtx (SDKSTR ("RegressionTest1_"));
        struct  FRED {
            static  void    DoIt (void* ignored)
            {
                for (int i = 1; i < 10; i++) {
                    Execution::Sleep (.001);
                }
            }
        };

        Thread  thread (bind (&FRED::DoIt, const_cast<char*> ("foo")));
        thread.Start ();
        thread.WaitForDone ();
    }
}

namespace   {
    recursive_mutex sharedCriticalSection_;
    void    RegressionTest2_ ()
    {
        Debug::TraceContextBumper traceCtx (SDKSTR ("RegressionTest2_"));

        // Make 2 concurrent threads, which share a critical section object to take turns updating a variable
        struct  FRED {
            static  void    DoIt (void* ignored)
            {
                int*    argP    =   reinterpret_cast<int*> (ignored);
                for (int i = 0; i < 10; i++) {
                    lock_guard<recursive_mutex> critSect (sharedCriticalSection_);
                    int tmp = *argP;
                    Execution::Sleep (.001);
                    //DbgTrace ("Updating value in thread id %d", ::GetCurrentThreadId  ());
                    *argP = tmp + 1;
                }
            }
        };

        int updaterValue    =   0;
        Thread  thread1 (bind (&FRED::DoIt, &updaterValue));
        Thread  thread2 (bind (&FRED::DoIt, &updaterValue));
        thread1.Start ();
        thread2.Start ();
        thread1.WaitForDone ();
        thread2.WaitForDone ();
        VerifyTestResult (updaterValue == 2 * 10);
    }
}

namespace   {
    WaitableEvent    sRegTest3Event_T1_ (WaitableEvent::eAutoReset);
    WaitableEvent    sRegTest3Event_T2_ (WaitableEvent::eAutoReset);
    namespace   WAITABLE_EVENTS_ {
        void    NOTIMEOUTS_ ()
        {
            Debug::TraceContextBumper traceCtx (SDKSTR ("pingpong threads with event.wait(NOTIMEOUTS)"));
            // Make 2 concurrent threads, which share 2 events to synchonize taking turns updating a variable
            struct  FRED1 {
                static  void    DoIt (void* ignored)
                {
                    int*    argP    =   reinterpret_cast<int*> (ignored);
                    for (int i = 0; i < 10; i++) {
                        sRegTest3Event_T1_.Wait ();
                        int tmp = *argP;
                        Execution::Sleep (.001);
                        // Since fred1/fred2 always take turns, and Fred1 always goes first...
                        VerifyTestResult (tmp % 2 == 0);
                        //DbgTrace ("FRED1: Updating value in of %d", tmp);
                        *argP = tmp + 1;
                        sRegTest3Event_T2_.Set ();
                    }
                }
            };
            struct  FRED2 {
                static  void    DoIt (void* ignored)
                {
                    int*    argP    =   reinterpret_cast<int*> (ignored);
                    for (int i = 0; i < 10; i++) {
                        sRegTest3Event_T2_.Wait ();
                        int tmp = *argP;
                        Execution::Sleep (.001);
                        //DbgTrace ("FRED2: Updating value in of %d", tmp);
                        *argP = tmp + 1;
                        sRegTest3Event_T1_.Set ();
                    }
                }
            };

            sRegTest3Event_T1_.Reset ();
            sRegTest3Event_T2_.Reset ();
            int updaterValue    =   0;
            Thread  thread1 (bind (&FRED1::DoIt, &updaterValue));
            Thread  thread2 (bind (&FRED2::DoIt, &updaterValue));
            thread1.Start ();
            thread2.Start ();
            // Both threads start out waiting - until we get things rolling telling one to start.
            // Then they pingpong back and forther
            sRegTest3Event_T1_.Set ();
            thread1.WaitForDone ();
            thread2.WaitForDone ();
            //DbgTrace ("Test3 - updaterValue = %d", updaterValue);
            // If there was a race - its unlikely you'd end up with exact 20 as your result
            VerifyTestResult (updaterValue == 2 * 10);
        }
        void    PingBackAndForthWithSimpleTimeouts_ ()
        {
            Debug::TraceContextBumper traceCtx (SDKSTR ("pingpong threads with event.wait(WITHTIMEOUT)"));
            // Make 2 concurrent threads, which share 2 events to synchonize taking turns updating a variable
            struct  FRED1 {
                static  void    DoIt (void* ignored)
                {
                    int*    argP    =   reinterpret_cast<int*> (ignored);
                    for (int i = 0; i < 10; i++) {
                        sRegTest3Event_T1_.Wait (5.0);
                        int tmp = *argP;
                        Execution::Sleep (.001);
                        // Since fred1/fred2 always take turns, and Fred1 always goes first...
                        VerifyTestResult (tmp % 2 == 0);
                        //DbgTrace ("FRED1: Updating value in of %d", tmp);
                        *argP = tmp + 1;
                        sRegTest3Event_T2_.Set ();
                    }
                }
            };
            struct  FRED2 {
                static  void    DoIt (void* ignored)
                {
                    int*    argP    =   reinterpret_cast<int*> (ignored);
                    for (int i = 0; i < 10; i++) {
                        sRegTest3Event_T2_.Wait (5.0);
                        int tmp = *argP;
                        Execution::Sleep (.001);
                        //DbgTrace ("FRED2: Updating value in of %d", tmp);
                        *argP = tmp + 1;
                        sRegTest3Event_T1_.Set ();
                    }
                }
            };

            sRegTest3Event_T1_.Reset ();
            sRegTest3Event_T2_.Reset ();
            int updaterValue    =   0;
            Thread  thread1 (bind (&FRED1::DoIt, &updaterValue));
            Thread  thread2 (bind (&FRED2::DoIt, &updaterValue));
            thread1.Start ();
            thread2.Start ();
            // Both threads start out waiting - until we get things rolling telling one to start.
            // Then they pingpong back and forther
            sRegTest3Event_T1_.Set ();
            thread1.WaitForDone ();
            thread2.WaitForDone ();
            //DbgTrace ("Test3 - updaterValue = %d", updaterValue);
            // If there was a race - its unlikely you'd end up with exact 20 as your result
            VerifyTestResult (updaterValue == 2 * 10);
        }
        void    TEST_TIMEOUT_EXECPETIONS_ ()
        {
            Debug::TraceContextBumper traceCtx (SDKSTR ("Event wait timeouts"));
            bool    passed  =   false;
            sRegTest3Event_T1_.Reset ();
            try {
                sRegTest3Event_T1_.Wait (0.5);  // should timeout
            }
            catch (const Execution::TimeOutException&) {
                passed = true;
            }
            catch (...) {
            }
            VerifyTestResult (passed);
        }
        void    TEST_DEADLOCK_BLOCK_WAIT_AND_ABORT_THREAD_WAITING ()
        {
            Debug::TraceContextBumper traceCtx (SDKSTR ("Deadlock block on waitable event and abort thread (thread cancelation)"));
            // Make 2 concurrent threads, which share 2 events to synchonize taking turns updating a variable
            struct  FRED1 {
                static  void    DoIt (void* ignored)
                {
                    sRegTest3Event_T1_.Wait (60.0);     // just has to be much more than the waits below
                }
            };

            sRegTest3Event_T1_.Reset ();
            int updaterValue    =   0;
            Thread  thread1 (bind (&FRED1::DoIt, &updaterValue));
            thread1.Start ();

            // At this point the thread SHOULD block and wait 30 seconds
            {
                const   Time::DurationSecondsType   kMargingOfError  =   .5;
                const   Time::DurationSecondsType   kWaitOnAbortFor  =   1.0;
                Time::DurationSecondsType   startTestAt     =   Time::GetTickCount ();
                Time::DurationSecondsType   caughtExceptAt  =   0;

                try {
                    thread1.WaitForDone (kWaitOnAbortFor);
                }
                catch (const Execution::TimeOutException&) {
                    caughtExceptAt =  Time::GetTickCount ();
                }
                Time::DurationSecondsType   expectedEndAt   =   startTestAt + kWaitOnAbortFor;
                VerifyTestResult (expectedEndAt - kMargingOfError <= caughtExceptAt and caughtExceptAt <= expectedEndAt + kMargingOfError);
            }

            // Now ABORT and WAITFORDONE - that should kill it nearly immediately
            {
#if     qEVENT_GCCTHREADS_LINUX_WAITBUG
                const   Time::DurationSecondsType   kMargingOfError  =   .9;
                const   Time::DurationSecondsType   kWaitOnAbortFor  =   5.0;   // because of BWA we used
#else
                const   Time::DurationSecondsType   kMargingOfError  =   .5;
                const   Time::DurationSecondsType   kWaitOnAbortFor  =   1.0;
#endif
                Time::DurationSecondsType   startTestAt     =   Time::GetTickCount ();
                try {
                    thread1.AbortAndWaitForDone (kWaitOnAbortFor);
                }
                catch (const Execution::TimeOutException&) {
                    VerifyTestResult (false);   // shouldn't fail to wait cuz we did abort
                }
                Time::DurationSecondsType   doneAt          =   Time::GetTickCount ();;
                Time::DurationSecondsType   expectedEndAt   =   startTestAt + kWaitOnAbortFor;
                VerifyTestResult (startTestAt <= doneAt and doneAt <= expectedEndAt + kMargingOfError);
            }

            // Thread MUST be done/terminated by this point
            VerifyTestResult (thread1.GetStatus () == Thread::Status::eCompleted);
        }
    }
    void    RegressionTest3_WaitableEvents_ ()
    {
        Debug::TraceContextBumper traceCtx (SDKSTR ("RegressionTest3_WaitableEvents_"));
        WAITABLE_EVENTS_::NOTIMEOUTS_ ();
        WAITABLE_EVENTS_::PingBackAndForthWithSimpleTimeouts_ ();
        WAITABLE_EVENTS_::TEST_TIMEOUT_EXECPETIONS_ ();
        WAITABLE_EVENTS_::TEST_DEADLOCK_BLOCK_WAIT_AND_ABORT_THREAD_WAITING ();
    }
}

namespace   {
    struct  data_ {};
    void    RegressionTest4_Lockable_ ()
    {
        Debug::TraceContextBumper traceCtx (SDKSTR ("RegressionTest4_Lockable_"));
        {
            Lockable<data_> x;
            Lockable<data_> y = data_ ();
            x = data_ ();
        }
        {
            Lockable<int>   x;
            Lockable<int>   y = 3;
            x = 4;
        }
        {
            // Make 2 concurrent threads, which update a lockable variable
            struct  FRED {
                static  void    DoIt (void* ignored)
                {
                    Lockable<int>*  argP    =   reinterpret_cast<Lockable<int>*> (ignored);
                    for (int i = 0; i < 10; i++) {
                        lock_guard<recursive_mutex> critSect (*argP);
                        int tmp = *argP;
                        Execution::Sleep (.01);
                        //DbgTrace ("Updating value in thread id %d", ::GetCurrentThreadId  ());
                        *argP = tmp + 1;
                    }
                }
            };
            Lockable<int>   updaterValue    =   0;
            Thread  thread1 (bind (&FRED::DoIt, &updaterValue));
            Thread  thread2 (bind (&FRED::DoIt, &updaterValue));
            thread1.Start ();
            thread2.Start ();
            thread1.WaitForDone ();
            thread2.WaitForDone ();
            VerifyTestResult (updaterValue == 2 * 10);
        }
    }
}

namespace   {
    void    RegressionTest5_Aborting_ ()
    {
        Debug::TraceContextBumper traceCtx (SDKSTR ("RegressionTest5_Aborting_"));
        {
            struct  FRED {
                static  void    DoIt ()
                {
                    while (true) {
                        Execution::CheckForThreadAborting ();
                    }
                }
            };
            Thread  thread (&FRED::DoIt);
            thread.Start ();
            try {
                thread.WaitForDone (0.3);   // should timeout
                VerifyTestResult (false);
            }
            catch (const Execution::TimeOutException&) {
                // GOOD
            }
            catch (...) {
                VerifyTestResult (false);
            }
            // Now - abort it, and wait
            thread.AbortAndWaitForDone ();
        }
#if     qPlatform_Windows
        {
            Thread  thread ([] () {
                while (true) {
                    // test alertable 'throw'
                    ::SleepEx (0, true);
                }
            });
            thread.Start ();
            try {
                thread.WaitForDone (0.3);   // should timeout
                VerifyTestResult (false);
            }
            catch (const Execution::TimeOutException&) {
                // GOOD
            }
            catch (...) {
                VerifyTestResult (false);
            }
            // Now - abort it, and wait
            thread.AbortAndWaitForDone ();
        }
#endif
    }
}

namespace   {
    void    RegressionTest6_ThreadWaiting_ ()
    {
        Debug::TraceContextBumper traceCtx (SDKSTR ("RegressionTest6_ThreadWaiting_"));
        struct  FRED {
            static  void    DoIt ()
            {
                Execution::Sleep (0.01);
            }
        };

        // Normal usage
        {
            Thread  thread (&FRED::DoIt);
            thread.Start ();
            thread.WaitForDone ();
        }

        // OK to never wait
        for (int i = 0; i < 100; ++i) {
            Thread  thread (&FRED::DoIt);
            thread.Start ();
        }

        // OK to wait and wait
        {
            Thread  thread (&FRED::DoIt);
            thread.Start ();
            thread.WaitForDone ();
            thread.WaitForDone (1.0);       // doesn't matter how long cuz its already DONE
            thread.WaitForDone ();
            thread.WaitForDone ();
        }
    }
}

namespace   {
    void    RegressionTest7_SimpleThreadPool_ ()
    {
        Debug::TraceContextBumper traceCtx (SDKSTR ("RegressionTest7_SimpleThreadPool_"));
        {
            ThreadPool  p;
            p.SetPoolSize (1);
            p.Abort ();
            p.WaitForDone ();
        }
        {
            ThreadPool  p;
            p.SetPoolSize (1);
            struct  FRED {
                static  void    DoIt (void* arg)
                {
                    int*    p   =   reinterpret_cast<int*> (arg);
                    (*p)++;
                }
            };
            int intVal  =   3;
            shared_ptr<Execution::IRunnable>    task    =   Execution::mkIRunnablePtr (bind (FRED::DoIt, &intVal));
            p.AddTask (task);
            p.WaitForTask (task);
            p.AbortAndWaitForDone ();
            VerifyTestResult (intVal == 4);
        }
    }
}

namespace   {
    void    RegressionTest8_ThreadPool_ ()
    {
        Debug::TraceContextBumper traceCtx (SDKSTR ("RegressionTest8_ThreadPool_"));
        // Make 2 concurrent tasks, which share a critical section object to take turns updating a variable
        struct  FRED {
            static  void    DoIt (void* ignored)
            {
                int*    argP    =   reinterpret_cast<int*> (ignored);
                for (int i = 0; i < 10; i++) {
                    lock_guard<recursive_mutex> critSect (sharedCriticalSection_);
                    int tmp = *argP;
                    Execution::Sleep (.01);
                    //DbgTrace ("Updating value in thread id %d", ::GetCurrentThreadId  ());
                    *argP = tmp + 1;
                }
            }
        };

        for (unsigned int threadPoolSize = 1; threadPoolSize < 10; ++threadPoolSize) {
            ThreadPool  p;
            p.SetPoolSize (threadPoolSize);
            int updaterValue    =   0;
            shared_ptr<Execution::IRunnable>    task1   =   Execution::mkIRunnablePtr (bind (&FRED::DoIt, &updaterValue));
            shared_ptr<Execution::IRunnable>    task2   =   Execution::mkIRunnablePtr (bind (&FRED::DoIt, &updaterValue));
            p.AddTask (task1);
            p.AddTask (task2);
            p.WaitForTask (task1);
            p.WaitForTask (task2);
            p.AbortAndWaitForDone ();
            VerifyTestResult (updaterValue == 2 * 10);
        }
    }
}

namespace   {
    void    RegressionTest9_ThreadsAbortingEarly_ ()
    {
        Debug::TraceContextBumper traceCtx (SDKSTR ("RegressionTest9_ThreadsAbortingEarly_"));
        // I was seeing SOME rare thread bug - trying to abort a thread which was itself trying to create a new thread - and was
        // between the create of thread and Abort
        struct  FRED {
            static  void    DoItInnerThread ()
            {
                Execution::Sleep (.01);
            }
            static  void    DoOuterThread ()
            {
                while (true) {
                    Thread t (DoItInnerThread);
                    Execution::Sleep (.02);
                    t.Start ();
                }
            }
        };
        Thread  thread (&FRED::DoOuterThread);
        thread.Start ();
        Execution::Sleep (.5);
        thread.AbortAndWaitForDone ();
    }
}

namespace {
    void    RegressionTest10_BlockingQueue_ ()
    {
        enum { START = 0, END = 100 };
        int expectedValue = (START + END) * (END - START + 1) / 2;
        int counter =   0;
        BlockingQueue<function<void()>> q;

        Thread  producerThread ([&q, &counter] () {
            for (int incBy = START; incBy <= END; ++incBy) {
                q.AddTail ([&counter, incBy] () { counter += incBy; });
            }
        });
        Thread  consumerThread ([&q] () {
            while (true) {
                function<void()>    f   =   q.RemoveHead ();
                f();
            }
        });
        producerThread.Start();
        consumerThread.Start();
        Time::DurationSecondsType killAt = 10.0 + Time::GetTickCount ();
        while (counter != expectedValue and Time::GetTickCount () < killAt) {
            Execution::Sleep (.5);
        }
        Verify (counter == expectedValue);
        producerThread.AbortAndWaitForDone ();
        consumerThread.AbortAndWaitForDone ();
    }
}

namespace {
    void    RegressionTest11_AbortSubAbort_ ()
    {
        auto    testFailToProperlyAbort = [] () {
            Thread  innerThread = [] () {
                Execution::Sleep (1000);
            };
            innerThread.SetThreadName (L"innerThread");
            Thread  testThread  =   [&innerThread] () {
                innerThread.Start ();
                Execution::Sleep (1000);
                innerThread.AbortAndWaitForDone ();
            };
            testThread.SetThreadName (L"testThread");
            testThread.Start ();
            Execution::Sleep (1);  // wait til both threads running and blocked in sleeps
            testThread.AbortAndWaitForDone ();
            // This is the BUG Thread::SuppressAbortInContext was meant to solve!
            VerifyTestResult (innerThread.GetStatus () == Thread::Status::eRunning);
            innerThread.AbortAndWaitForDone ();
        };
        auto    testInnerThreadProperlyShutDownByOuterThread = [] () {
            Thread  innerThread = [] () {
                Execution::Sleep (1000);
            };
            innerThread.SetThreadName (L"innerThread");
            Thread  testThread = [&innerThread] () {
                innerThread.Start ();
                Finally cleanup ([&innerThread] () {
                    Thread::SuppressAbortInContext  suppressAborts;
                    innerThread.AbortAndWaitForDone ();
                });
                Execution::Sleep (1000);
            };
            testThread.SetThreadName (L"testThread");
            testThread.Start ();
            Execution::Sleep (1);   // wait til both threads running and blocked in sleeps
            // This is the BUG Thread::SuppressAbortInContext was meant to solve!
            testThread.AbortAndWaitForDone ();
            VerifyTestResult (innerThread.GetStatus () == Thread::Status::eCompleted);
        };
        testFailToProperlyAbort ();
        testInnerThreadProperlyShutDownByOuterThread ();
    }
}

namespace {
    void    RegressionTest12_WaitAny_ ()
    {
        // EXPERIMENTAL
        WaitableEvent we1 (WaitableEvent::eAutoReset);
        WaitableEvent we2 (WaitableEvent::eAutoReset);
        Thread t1 = [&we1] () {
            Execution::Sleep (1.0);
            we1.Set ();
        };
        Thread t2 = [&we2] () {
            Execution::Sleep (0.1);
            we2.Set ();
        };
        Time::DurationSecondsType   startAt = Time::GetTickCount ();
        t1.Start ();
        t2.Start ();
        VerifyTestResult (WaitableEvent::WaitForAny (Sequence<WaitableEvent*> ({&we1, &we2})) == set<WaitableEvent*> ({&we2}));
        Time::DurationSecondsType   timeTaken = Time::GetTickCount () - startAt;
        VerifyTestResult (timeTaken < 0.5);     // make sure we didnt wait for the 1.0 second on first thread
        // They capture so must wait for them to complete
        t1.AbortAndWaitForDone ();
        t2.AbortAndWaitForDone ();
    }
}

namespace {
    void    RegressionTest13_WaitAll_ ()
    {
        // EXPERIMENTAL
        WaitableEvent we1 (WaitableEvent::eAutoReset);
        WaitableEvent we2 (WaitableEvent::eAutoReset);
        bool w1Fired = false;
        bool w2Fired = false;
        Thread t1 = [&we1, &w1Fired] () {
            Execution::Sleep (0.5);
            w1Fired = true;
            we1.Set ();
        };
        Thread t2 = [&we2, &w2Fired] () {
            Execution::Sleep (0.1);
            w2Fired = true;
            we2.Set ();
        };
        Time::DurationSecondsType   startAt = Time::GetTickCount ();
        t2.Start ();
        t1.Start ();
        WaitableEvent::WaitForAll (Sequence<WaitableEvent*> ({&we1, &we2}));
        VerifyTestResult (w1Fired and w2Fired);
        // They capture so must wait for them to complete
        t1.AbortAndWaitForDone ();
        t2.AbortAndWaitForDone ();
    }
}

namespace {
    void    RegressionTest14_SpinLock_ ()
    {
        SpinLock lock;
        int     sum =   0;
        Thread t1 = [&lock, &sum] () {
            for (int i = 0; i < 100; ++i) {
                Execution::Sleep (0.001);
                lock_guard<SpinLock> critSec (lock);
                sum += i;
            }
        };
        Thread t2 = [&lock, &sum] () {
            for (int i = 0; i < 100; ++i) {
                Execution::Sleep (0.001);
                lock_guard<SpinLock> critSec (lock);
                sum -= i;
            }
        };
        t1.Start ();
        t2.Start ();
        t1.WaitForDone ();
        t2.WaitForDone ();
        VerifyTestResult (sum == 0);
    }
}

namespace   {
    void    DoRegressionTests_ ()
    {
        RegressionTest1_ ();
        RegressionTest2_ ();
        RegressionTest3_WaitableEvents_ ();
        RegressionTest4_Lockable_ ();
        RegressionTest5_Aborting_ ();
        RegressionTest6_ThreadWaiting_ ();
        RegressionTest7_SimpleThreadPool_ ();
        RegressionTest8_ThreadPool_ ();
        RegressionTest9_ThreadsAbortingEarly_ ();
        RegressionTest10_BlockingQueue_ ();
        RegressionTest11_AbortSubAbort_ ();
        RegressionTest12_WaitAny_ ();
        RegressionTest13_WaitAll_ ();
        RegressionTest14_SpinLock_ ();
    }
}

int     main (int argc, const char* argv[])
{
    Stroika::TestHarness::Setup ();
    Stroika::TestHarness::PrintPassOrFail (DoRegressionTests_);
    return EXIT_SUCCESS;
}
<commit_msg>decent first draft of ThreadSafetyBuiltinObject regtest - clearly easily reproduces failures<commit_after>/*
 * Copyright(c) Sophist Solutions, Inc. 1990-2014.  All rights reserved
 */
//  TEST    Foundation::Execution::ThreadSafetyBuiltinObject
#include    "Stroika/Foundation/StroikaPreComp.h"

#include    <iostream>
#include    <mutex>

#include    "Stroika/Foundation/Characters/String.h"
#include    "Stroika/Foundation/Containers/Sequence.h"
#include    "Stroika/Foundation/Containers/Set.h"
#include    "Stroika/Foundation/Execution/ExternallySynchronizedLock.h"
#include    "Stroika/Foundation/Execution/Sleep.h"
#include    "Stroika/Foundation/Execution/SpinLock.h"
#include    "Stroika/Foundation/Execution/Thread.h"
#include    "Stroika/Foundation/Execution/ThreadPool.h"
#include    "Stroika/Foundation/Execution/WaitableEvent.h"
#include    "Stroika/Foundation/Execution/TimeOutException.h"
#include    "Stroika/Foundation/Math/Common.h"

#include    "../TestHarness/TestHarness.h"

using   namespace   Stroika::Foundation;
using   namespace   Characters;
using   namespace   Containers;

using   Execution::ExternallySynchronizedLock;
using   Execution::Thread;
using   Execution::WaitableEvent;

namespace   {
    namespace AssignAndIterateAtSameTimeTest_ {

        template    <typename ITERABLE_TYPE>
        void    DoIt_ (ITERABLE_TYPE elt1, ITERABLE_TYPE elt2, unsigned int repeatCount)
        {
            /*
             *  To REALLY this this code for thread-safety, use ExternallySynchronizedLock, but to verify it works
             *  without worrying about races, just use mutex.
             */
            //ExternallySynchronizedLock lock;
            mutex lock;

            ITERABLE_TYPE   oneToKeepOverwriting = elt1;
            using ElementType   =   typename ITERABLE_TYPE::ElementType;
            Thread  iterateThread = [&oneToKeepOverwriting, repeatCount, &lock] () {
                for (unsigned int i = 0; i < repeatCount; ++i) {
                    lock_guard<decltype(lock)> critSec (lock);
                    for (ElementType e :  oneToKeepOverwriting) {
                        ElementType e2 = e; // do something
                    }
                }
            };
            Thread  overwriteThread = [&oneToKeepOverwriting, elt1, elt2, repeatCount, &lock] () {
                for (unsigned int i = 0; i < repeatCount; ++i) {
                    for (int ii = 0; ii <= 100; ++ii) {
                        if (Math::IsOdd (ii)) {
                            lock_guard<decltype(lock)> critSec (lock);
                            oneToKeepOverwriting = elt1;
                        }
                        else {
                            lock_guard<decltype(lock)> critSec (lock);
                            oneToKeepOverwriting = elt2;
                        }
                    }
                }
            };
            iterateThread.Start ();
            overwriteThread.Start ();
            iterateThread.WaitForDone ();
            overwriteThread.WaitForDone ();
        }
    }

    void    AssignAndIterateAtSameTimeTest_1_ ()
    {
        Debug::TraceContextBumper traceCtx (SDKSTR ("AssignAndIterateAtSameTimeTest_1_"));
        AssignAndIterateAtSameTimeTest_::DoIt_<String> (String (L"123456789"), String (L"abcdedfghijkqlmopqrstuvwxyz"), 500);
        AssignAndIterateAtSameTimeTest_::DoIt_<Sequence<int>> (Sequence<int> ({1, 3, 4, 5, 6, 33, 12, 13}), Sequence<int> ({4, 5, 6, 33, 12, 13, 1, 3, 99, 33, 4, 5}), 500);
        AssignAndIterateAtSameTimeTest_::DoIt_<Set<int>> (Set<int> ({1, 3, 4, 5, 6, 33, 12, 13}), Set<int> ({4, 5, 6, 33, 12, 13, 34, 388, 3, 99, 33, 4, 5}), 500);
    }
}

namespace   {
    void    DoRegressionTests_ ()
    {
        AssignAndIterateAtSameTimeTest_1_ ();
    }
}

int     main (int argc, const char* argv[])
{
    Stroika::TestHarness::Setup ();
    Stroika::TestHarness::PrintPassOrFail (DoRegressionTests_);
    return EXIT_SUCCESS;
}
<|endoftext|>


<commit_before>// Copyright 2018-2020 Intel Corporation
// SPDX-License-Identifier: Apache-2.0

#include "BaseFixture.h"
#include "rkcommon/utility/getEnvVar.h"
#ifdef _WIN32
#ifndef NOMINMAX
#define NOMINMAX
#endif
#include <conio.h>
#include <windows.h>
#endif

// Test init/shutdown cycle time //////////////////////////////////////////////

static void ospInit_ospShutdown(benchmark::State &state)
{
  ospShutdown();

  for (auto _ : state) {
    ospInit();
    ospShutdown();
  }
  state.SetItemsProcessed(state.iterations());

  ospInit();
}

BENCHMARK(ospInit_ospShutdown)->Unit(benchmark::kMillisecond);

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

// based on BENCHMARK_MAIN() macro from benchmark.h
int main(int argc, char **argv)
{
#ifdef _WIN32
  bool waitForKey = false;
  CONSOLE_SCREEN_BUFFER_INFO csbi;
  if (GetConsoleScreenBufferInfo(GetStdHandle(STD_OUTPUT_HANDLE), &csbi)) {
    // detect standalone console: cursor at (0,0)?
    waitForKey = csbi.dwCursorPosition.X == 0 && csbi.dwCursorPosition.Y == 0;
  }
#endif

  ospInit(&argc, (const char **)argv);

  auto DIR = utility::getEnvVar<std::string>("OSPRAY_BENCHMARK_IMG_DIR");
  BaseFixture::dumpFinalImageDir = DIR.value_or("");

  ::benchmark::Initialize(&argc, argv);
  if (::benchmark::ReportUnrecognizedArguments(argc, argv))
    return 1;
  ::benchmark::RunSpecifiedBenchmarks();

  ospShutdown();

#ifdef _WIN32
  if (waitForKey) {
    printf("\n\tpress any key to exit");
    _getch();
  }
#endif

  return 0;
}
<commit_msg>added elaborative --help to ospBenchmark<commit_after>// Copyright 2018-2020 Intel Corporation
// SPDX-License-Identifier: Apache-2.0

#include "BaseFixture.h"
#include "rkcommon/utility/getEnvVar.h"
#ifdef _WIN32
#ifndef NOMINMAX
#define NOMINMAX
#endif
#include <conio.h>
#include <windows.h>
#endif

#include <iostream>
#include <string>

// Test init/shutdown cycle time //////////////////////////////////////////////

static void ospInit_ospShutdown(benchmark::State &state)
{
  ospShutdown();

  for (auto _ : state) {
    ospInit();
    ospShutdown();
  }
  state.SetItemsProcessed(state.iterations());

  ospInit();
}

BENCHMARK(ospInit_ospShutdown)->Unit(benchmark::kMillisecond);

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

// based on BENCHMARK_MAIN() macro from benchmark.h
int main(int argc, char **argv)
{
#ifdef _WIN32
  bool waitForKey = false;
  CONSOLE_SCREEN_BUFFER_INFO csbi;
  if (GetConsoleScreenBufferInfo(GetStdHandle(STD_OUTPUT_HANDLE), &csbi)) {
    // detect standalone console: cursor at (0,0)?
    waitForKey = csbi.dwCursorPosition.X == 0 && csbi.dwCursorPosition.Y == 0;
  }
#endif

  // As there is no other way of customizing help output
  // we have to detect `--help` by ourselves
  for (int i = 1; i < argc; i++) {
    if (std::string(argv[i]) == "--help") {
      std::cout
          << "The ospBenchmark is a performance measurement tool that "
             "allows to assess the Intel OSPRay library performance on a target "
             "hardware. It consists of many workloads that can be listed with "
             "[--benchmark_list_tests=true] parameter and then selected for run "
             "with [--benchmark_filter=<regex>] parameter. All test assets like "
             "meshes or textures are generated procedurally during workload "
             "initialization phase. If a test renders a frame it is stored "
             "to an offscreen frame buffer."
          << std::endl
          << std::endl;

      std::cout
          << "After tests completion a results table is printed. Each "
             "table row corresponds to a single test or a single test "
             "repetition. Number of repetitions can be controlled with "
             "[--benchmark_repetitions=<num_repetitions>] parameter. Each "
             "repetition completely recreates frame buffer, world, renderer "
             "and camera. The table has the following columns:"
          << std::endl;

      std::cout << "  'Benchmark' - the name of a test" << std::endl;
      std::cout << "  'Time' - single iteration wall clock time" << std::endl;
      std::cout
          << "  'CPU' - single iteration CPU time spend by the main thread"
          << std::endl;
      std::cout
          << "  'Iterations' - number of rendered frames, determined adaptively "
             "to test for specified minimum time"
          << std::endl;
      std::cout << "  'UserCounters' - frames per second value" << std::endl
                << std::endl;

      std::cout << "The list of all supported parameters:" << std::endl;
    }
  }

  ospInit(&argc, (const char **)argv);

  auto DIR = utility::getEnvVar<std::string>("OSPRAY_BENCHMARK_IMG_DIR");
  BaseFixture::dumpFinalImageDir = DIR.value_or("");

  ::benchmark::Initialize(&argc, argv);
  if (::benchmark::ReportUnrecognizedArguments(argc, argv))
    return 1;
  ::benchmark::RunSpecifiedBenchmarks();

  ospShutdown();

#ifdef _WIN32
  if (waitForKey) {
    printf("\n\tpress any key to exit");
    _getch();
  }
#endif

  return 0;
}
<|endoftext|>


<commit_before>
/**
 * @file SunPosition.hpp
 * Returns the approximate position of the Sun at the given epoch in the
 * ECEF system.
 */

//============================================================================
//
//  This file is part of GPSTk, the GPS Toolkit.
//
//  The GPSTk is free software; you can redistribute it and/or modify
//  it under the terms of the GNU Lesser General Public License as published
//  by the Free Software Foundation; either version 2.1 of the License, or
//  any later version.
//
//  The GPSTk 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 GPSTk; if not, write to the Free Software Foundation,
//  Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
//
//  Dagoberto Salazar - gAGE ( http://www.gage.es ). 2007
//
//============================================================================

#include "SunPosition.hpp"

namespace gpstk
{

    // Returns the position of Sun ECEF coordinates (meters) at the indicated time.
    // @param[in] t the time to look up
    // @return the Xvt of the Sun at time
    // @throw InvalidRequest If the request can not be completed for any
    //    reason, this is thrown. The text may have additional
    //    information as to why the request failed.
    Xvt SunPosition::getXvt(const DayTime& t) const throw(InvalidRequest)
    {

        // Here we will store the results
        Xvt res;

        res = sun_position_CIS(t);
        res = CIS2CTS(res, t);

        return res;
    } // End SunPosition::getXvt

    /* Function to compute Sun position in CIS system (coordinates in meters)
     * @param t Epoch
     */
    Xvt sun_position_CIS(const DayTime& t)
    {
        // Astronomical Unit value (AU), in meters
        const double AU_CONST(1.49597870e11);

        //Mean Earth-Moon barycenter (EMB) distance (AU)
        const double REMB(3.12e-5);

        // Compute the years, and fraction of year, pased since J1900.0
        int y(t.year());    // Current year
        int doy(t.DOY());   // Day of current year
        double fd( (t.secOfDay()/86400.0 ) );   // Fraction of day
        int years( (y - 1900) );    // Integer number of years since J1900.0
        int iy4( ( ((y%4)+4)%4 ) ); // Is it a leap year?
        // Compute fraction of year
        double yearfrac = ( ( (4.0*(doy-1.0/((double)iy4+1.0)) - (double)iy4 - 2.0 ) + 4.0 * fd ) / 1461.0 );
        double time(years+yearfrac);

        // Compute the geometric mean longitude of the Sun
        double* intpar;
        double elm( modf((4.881628 + TWO_PI*yearfrac + 0.0001342*time)/TWO_PI, intpar) );

        // Mean longitude of perihelion
        double gamma(4.90823 + 3.0005e-4*time);

        // Mean anomaly
        double em(elm-gamma);

        // Mean obliquity
        double eps0(0.40931975 - 2.27e-6*time);

        // Eccentricity
        double e(0.016751 - 4.2e-7*time);
        double esq(e*e);

        // True anomaly
        double v(em + 2.0*e*sin(em) + 1.25*esq*sin(2.0*em));

        // True ecliptic longitude
        double elt(v+gamma);

        // True distance
        double r( (1.0 - esq)/(1.0 + e*cos(v)) );

        // Moon's mean longitude
        modf((4.72 + 83.9971*time)/TWO_PI, intpar);
        double elmm(*intpar);

        // Useful definitions
        double coselt(cos(elt));
        double sineps(sin(eps0));
        double coseps(cos(eps0));
        double w1(-r*sin(elt));
        double selmm(sin(elmm));
        double celmm(cos(elm));

        Xvt result;

        // Sun position is the opposite of Earth position
        result.x.theArray[0] = (r*coselt+REMB*celmm)*AU_CONST;
        result.x.theArray[1] = (REMB*selmm-w1)*coseps*AU_CONST;
        result.x.theArray[2] = (-w1*sineps)*AU_CONST;

        return result;
    } // End sun_position_CIS()

    /* Function to change from CIS to CTS(ECEF) coordinate system (coordinates in meters)
     * @param posCis    Coordinates in CIS system (in meters).
     * @param t         Epoch
     */
    Xvt CIS2CTS(const Xvt posCIS, const DayTime& t)
    {

        // Angle of Earth rotation, in radians
        double ts( UTC2SID(t)*TWO_PI/24.0 );

        Xvt res;

        res.x.theArray[0] = cos(ts)*posCIS.x.theArray[0] + sin(ts)*posCIS.x.theArray[1];
        res.x.theArray[1] = -sin(ts)*posCIS.x.theArray[0] + cos(ts)*posCIS.x.theArray[1];
        res.x.theArray[2] = posCIS.x.theArray[2];

        return res;
    } // End CIS2CTS()

    /* Function to convert from UTC to sidereal time
     * @param t         Epoch
     *
     * @return sidereal time in hours
     */
    double UTC2SID(const DayTime& t)
    {

        // Fraction of day, in hours
        double frofday( t.secOfDay()/3600.0 );

        // Temporal value, in centuries
        double tt( (t.JD() - 2451545.0)/36525.0 );

        double sid( 24110.54841 + tt*( (8640184.812866) + tt*( (0.093104) - (6.2e-6*tt)) ) );

        double* intpar;
        sid = modf( (sid/3600.0 + frofday)/24.0, intpar);

        if(sid<0.0) sid = sid + 24.0;

        return sid;
    }

} // end namespace gpstk
<commit_msg>Improvements in SunPosition. It is not ready yet: Some bugs remain.<commit_after>
/**
 * @file SunPosition.hpp
 * Returns the approximate position of the Sun at the given epoch in the
 * ECEF system.
 */

//============================================================================
//
//  This file is part of GPSTk, the GPS Toolkit.
//
//  The GPSTk is free software; you can redistribute it and/or modify
//  it under the terms of the GNU Lesser General Public License as published
//  by the Free Software Foundation; either version 2.1 of the License, or
//  any later version.
//
//  The GPSTk 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 GPSTk; if not, write to the Free Software Foundation,
//  Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
//
//  Dagoberto Salazar - gAGE ( http://www.gage.es ). 2007
//
//============================================================================

#include "SunPosition.hpp"

namespace gpstk
{

    // Returns the position of Sun ECEF coordinates (meters) at the indicated time.
    // @param[in] t the time to look up
    // @return the Xvt of the Sun at time
    // @throw InvalidRequest If the request can not be completed for any
    //    reason, this is thrown. The text may have additional
    //    information as to why the request failed.
    Xvt SunPosition::getXvt(const DayTime& t) const throw(InvalidRequest)
    {

        // Here we will store the results
        Xvt res;

        res = sun_position_CIS(t);
        res = CIS2CTS(res, t);

        return res;
    } // End SunPosition::getXvt

    /* Function to compute Sun position in CIS system (coordinates in meters)
     * @param t Epoch
     */
    Xvt sun_position_CIS(const DayTime& t)
    {
        // Astronomical Unit value (AU), in meters
        const double AU_CONST(1.49597870e11);

        //Mean Earth-Moon barycenter (EMB) distance (AU)
        const double REMB(3.12e-5);

        // Compute the years, and fraction of year, pased since J1900.0
        int y(t.year());    // Current year
        int doy(t.DOY());   // Day of current year
        double fd( (t.secOfDay()/3600.0 ) );   // Fraction of day, in hours
        int years( (y - 1900) );    // Integer number of years since J1900.0
        int iy4( ( ((y%4)+4)%4 ) ); // Is it a leap year?
        // Compute fraction of year
        double yearfrac = ( ( (4.0*(doy-1.0/(iy4+1)) - iy4 - 2 ) + 4.0 * fd ) / 1461.0 );
        double time(years+yearfrac);

        // Compute the geometric mean longitude of the Sun
        double elm( fmod((4.881628 + TWO_PI*yearfrac + 0.0001342*time), TWO_PI) );

        // Mean longitude of perihelion
        double gamma(4.90823 + 0.00030005*time);

        // Mean anomaly
        double em(elm-gamma);

        // Mean obliquity
        double eps0(0.40931975 - 2.27e-6*time);

        // Eccentricity
        double e(0.016751 - 4.2e-7*time);
        double esq(e*e);

        // True anomaly
        double v(em + 2.0*e*sin(em) + 1.25*esq*sin(2.0*em));

        // True ecliptic longitude
        double elt(v+gamma);

        // True distance
        double r( (1.0 - esq)/(1.0 + e*cos(v)) );

        // Moon's mean longitude
        double elmm( fmod((4.72 + 83.9971*time),TWO_PI) );

        // Useful definitions
        double coselt(cos(elt));
        double sineps(sin(eps0));
        double coseps(cos(eps0));
        double w1(-r*sin(elt));
        double selmm(sin(elmm));
        double celmm(cos(elm));

        Xvt result;

        // Sun position is the opposite of Earth position
        result.x.theArray[0] = (r*coselt+REMB*celmm)*AU_CONST;
        result.x.theArray[1] = (REMB*selmm-w1)*coseps*AU_CONST;
        result.x.theArray[2] = (-w1*sineps)*AU_CONST;

        return result;
    } // End sun_position_CIS()

    /* Function to change from CIS to CTS(ECEF) coordinate system (coordinates in meters)
     * @param posCis    Coordinates in CIS system (in meters).
     * @param t         Epoch
     */
    Xvt CIS2CTS(const Xvt posCIS, const DayTime& t)
    {

        // Angle of Earth rotation, in radians
        double ts( UTC2SID(t)*TWO_PI/24.0 );

        Xvt res;

        res.x.theArray[0] = cos(ts)*posCIS.x.theArray[0] + sin(ts)*posCIS.x.theArray[1];
        res.x.theArray[1] = -sin(ts)*posCIS.x.theArray[0] + cos(ts)*posCIS.x.theArray[1];
        res.x.theArray[2] = posCIS.x.theArray[2];

        return res;
    } // End CIS2CTS()

    /* Function to convert from UTC to sidereal time
     * @param t         Epoch
     *
     * @return sidereal time in hours
     */
    double UTC2SID(const DayTime& t)
    {

        double y(t.year()-1.0);
        double m(13.0);
        double d(t.DOY());
        double h(t.secOfDay()/3600.0);  // Hours of day (decimal)
        double frofday (t.secOfDay()/86400.0);        // Fraction of day

        // Compute Julian Day, including decimals
        double jd(floor(365.25*y) + floor(30.6001*(m+1.0)) + d + frofday + 1720981.5);

        // Temporal value, in centuries
        double tt( (jd - 2451545.0)/36525.0 );

        double sid( 24110.54841 + tt*( (8640184.812866) + tt*( (0.093104) - (6.2e-6*tt)) ) );

        sid = sid/3600.0 + h;
        sid = fmod(sid,24.0);

        if (sid < 0.0) sid+=24.0;

        return sid;
    }

} // end namespace gpstk
<|endoftext|>


<commit_before>
/**
 * @file SunPosition.cpp
 * Returns the approximate position of the Sun at the given epoch in the
 * ECEF system.
 */

//============================================================================
//
//  This file is part of GPSTk, the GPS Toolkit.
//
//  The GPSTk is free software; you can redistribute it and/or modify
//  it under the terms of the GNU Lesser General Public License as published
//  by the Free Software Foundation; either version 2.1 of the License, or
//  any later version.
//
//  The GPSTk 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 GPSTk; if not, write to the Free Software Foundation,
//  Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
//
//  Dagoberto Salazar - gAGE ( http://www.gage.es ). 2007
//
//============================================================================

#include "SunPosition.hpp"

namespace gpstk
{

    // Returns the position of Sun ECEF coordinates (meters) at the indicated time.
    // @param[in] t the time to look up
    // @return the Xvt of the Sun at time
    // @throw InvalidRequest If the request can not be completed for any
    //    reason, this is thrown. The text may have additional
    //    information as to why the request failed.
    Xvt SunPosition::getXvt(const DayTime& t) const throw(InvalidRequest)
    {

        // Test if the time interval is correct
        if ( (t < initialTime) || (t > finalTime) )
        {
            InvalidRequest ir("Provided epoch is out of bounds.");
            GPSTK_THROW(ir);
        }

        // Here we will store the results
        Xvt res;

        res = SunPosition::getXvtCIS(t);
        res = CIS2CTS(res, t);

        return res;
    } // End SunPosition::getXvt

    /* Function to compute Sun position in CIS system (coordinates in meters)
     * @param t Epoch
     */
    Xvt SunPosition::getXvtCIS(const DayTime& t) const throw(InvalidRequest)
    {

        // Test if the time interval is correct
        if ( (t < initialTime) || (t > finalTime) )
        {
            InvalidRequest ir("Provided epoch is out of bounds.");
            GPSTK_THROW(ir);
        }

        // Astronomical Unit value (AU), in meters
        const double AU_CONST(1.49597870e11);

        //Mean Earth-Moon barycenter (EMB) distance (AU)
        const double REMB(3.12e-5);

        // Compute the years, and fraction of year, pased since J1900.0
        int y(t.year());    // Current year
        int doy(t.DOY());   // Day of current year
        double fd( (t.secOfDay()/86400.0 ) );   // Fraction of day
        int years( (y - 1900) );    // Integer number of years since J1900.0
        int iy4( ( ((y%4)+4)%4 ) ); // Is it a leap year?
        // Compute fraction of year
        double yearfrac = ( ( (double)(4*(doy-1/(iy4+1)) - iy4 - 2) + 4.0 * fd ) / 1461.0 );
        double time(years+yearfrac);

        // Compute the geometric mean longitude of the Sun
        double elm( fmod((4.881628 + TWO_PI*yearfrac + 0.0001342*time), TWO_PI) );

        // Mean longitude of perihelion
        double gamma(4.90823 + 0.00030005*time);

        // Mean anomaly
        double em(elm-gamma);

        // Mean obliquity
        double eps0(0.40931975 - 2.27e-6*time);

        // Eccentricity
        double e(0.016751 - 4.2e-7*time);
        double esq(e*e);

        // True anomaly
        double v(em + 2.0*e*sin(em) + 1.25*esq*sin(2.0*em));

        // True ecliptic longitude
        double elt(v+gamma);

        // True distance
        double r( (1.0 - esq)/(1.0 + e*cos(v)) );

        // Moon's mean longitude
        double elmm( fmod((4.72 + 83.9971*time),TWO_PI) );

        // Useful definitions
        double coselt(cos(elt));
        double sineps(sin(eps0));
        double coseps(cos(eps0));
        double w1(-r*sin(elt));
        double selmm(sin(elmm));
        double celmm(cos(elmm));

        Xvt result;

        // Sun position is the opposite of Earth position
        result.x.theArray[0] = (r*coselt+REMB*celmm)*AU_CONST;
        result.x.theArray[1] = (REMB*selmm-w1)*coseps*AU_CONST;
        result.x.theArray[2] = (-w1*sineps)*AU_CONST;

        return result;
    } // End SunPosition::getXvtCIS()

} // end namespace gpstk
<commit_msg>Small type casting modification.<commit_after>
/**
 * @file SunPosition.cpp
 * Returns the approximate position of the Sun at the given epoch in the
 * ECEF system.
 */

//============================================================================
//
//  This file is part of GPSTk, the GPS Toolkit.
//
//  The GPSTk is free software; you can redistribute it and/or modify
//  it under the terms of the GNU Lesser General Public License as published
//  by the Free Software Foundation; either version 2.1 of the License, or
//  any later version.
//
//  The GPSTk 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 GPSTk; if not, write to the Free Software Foundation,
//  Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
//
//  Dagoberto Salazar - gAGE ( http://www.gage.es ). 2007
//
//============================================================================

#include "SunPosition.hpp"

namespace gpstk
{

    // Returns the position of Sun ECEF coordinates (meters) at the indicated time.
    // @param[in] t the time to look up
    // @return the Xvt of the Sun at time
    // @throw InvalidRequest If the request can not be completed for any
    //    reason, this is thrown. The text may have additional
    //    information as to why the request failed.
    Xvt SunPosition::getXvt(const DayTime& t) const throw(InvalidRequest)
    {

        // Test if the time interval is correct
        if ( (t < initialTime) || (t > finalTime) )
        {
            InvalidRequest ir("Provided epoch is out of bounds.");
            GPSTK_THROW(ir);
        }

        // Here we will store the results
        Xvt res;

        res = SunPosition::getXvtCIS(t);
        res = CIS2CTS(res, t);

        return res;
    } // End SunPosition::getXvt

    /* Function to compute Sun position in CIS system (coordinates in meters)
     * @param t Epoch
     */
    Xvt SunPosition::getXvtCIS(const DayTime& t) const throw(InvalidRequest)
    {

        // Test if the time interval is correct
        if ( (t < initialTime) || (t > finalTime) )
        {
            InvalidRequest ir("Provided epoch is out of bounds.");
            GPSTK_THROW(ir);
        }

        // Astronomical Unit value (AU), in meters
        const double AU_CONST(1.49597870e11);

        //Mean Earth-Moon barycenter (EMB) distance (AU)
        const double REMB(3.12e-5);

        // Compute the years, and fraction of year, pased since J1900.0
        int y(t.year());    // Current year
        int doy(t.DOY());   // Day of current year
        double fd( (t.secOfDay()/86400.0 ) );   // Fraction of day
        int years( (y - 1900) );    // Integer number of years since J1900.0
        int iy4( ( ((y%4)+4)%4 ) ); // Is it a leap year?
        // Compute fraction of year
        double yearfrac = ( ( static_cast<double>(4*(doy-1/(iy4+1)) - iy4 - 2) + 4.0 * fd ) / 1461.0 );
        double time(years+yearfrac);

        // Compute the geometric mean longitude of the Sun
        double elm( fmod((4.881628 + TWO_PI*yearfrac + 0.0001342*time), TWO_PI) );

        // Mean longitude of perihelion
        double gamma(4.90823 + 0.00030005*time);

        // Mean anomaly
        double em(elm-gamma);

        // Mean obliquity
        double eps0(0.40931975 - 2.27e-6*time);

        // Eccentricity
        double e(0.016751 - 4.2e-7*time);
        double esq(e*e);

        // True anomaly
        double v(em + 2.0*e*sin(em) + 1.25*esq*sin(2.0*em));

        // True ecliptic longitude
        double elt(v+gamma);

        // True distance
        double r( (1.0 - esq)/(1.0 + e*cos(v)) );

        // Moon's mean longitude
        double elmm( fmod((4.72 + 83.9971*time),TWO_PI) );

        // Useful definitions
        double coselt(cos(elt));
        double sineps(sin(eps0));
        double coseps(cos(eps0));
        double w1(-r*sin(elt));
        double selmm(sin(elmm));
        double celmm(cos(elmm));

        Xvt result;

        // Sun position is the opposite of Earth position
        result.x.theArray[0] = (r*coselt+REMB*celmm)*AU_CONST;
        result.x.theArray[1] = (REMB*selmm-w1)*coseps*AU_CONST;
        result.x.theArray[2] = (-w1*sineps)*AU_CONST;

        return result;
    } // End SunPosition::getXvtCIS()

} // end namespace gpstk
<|endoftext|>


<commit_before>//Copyright (c) 2017 Ultimaker B.V.
//CuraEngine is released under the terms of the AGPLv3 or higher.

#include "utils/intpoint.h" //To normalize vectors.
#include "utils/math.h" //For round_up_divide and PI.
#include "utils/MinimumSpanningTree.h" //For connecting the correct nodes together to form an efficient tree.
#include "utils/polygonUtils.h" //For moveInside.

#include "TreeSupport.h"

#define SQRT_2 1.4142135623730950488 //Square root of 2.
#define CIRCLE_RESOLUTION 10 //The number of vertices in each circle.

namespace cura
{

TreeSupport::TreeSupport()
{
}

void TreeSupport::generateSupportAreas(SliceDataStorage& storage)
{
    std::vector<std::unordered_set<Point>> contact_points;
    std::vector<std::unordered_map<Point, Node>> contact_nodes;
    contact_points.reserve(storage.support.supportLayers.size());
    contact_nodes.reserve(storage.support.supportLayers.size());
    for (size_t layer_nr = 0; layer_nr < storage.support.supportLayers.size(); layer_nr++) //Generate empty layers to store the points in.
    {
        contact_points.emplace_back();
        contact_nodes.emplace_back();
    }
    for (SliceMeshStorage& mesh : storage.meshes)
    {
        if (!mesh.getSettingBoolean("support_tree_enable"))
        {
            return;
        }
        generateContactPoints(mesh, contact_points, contact_nodes);
    }

    //Generate areas that have to be avoided.
    const coord_t layer_height = storage.getSettingInMicrons("layer_height");
    const double angle = storage.getSettingInAngleRadians("support_tree_angle");
    const coord_t maximum_move_distance = tan(angle) * layer_height;
    std::vector<Polygons> model_collision_tips; //Areas that have to be avoided by the tips of the branches.
    std::vector<Polygons> model_collision_base; //Areas that have to be avoided by the normal parts of the branches.
    const coord_t branch_radius = storage.getSettingInMicrons("support_tree_branch_diameter") >> 1;
    const coord_t xy_distance = storage.getSettingInMicrons("support_xy_distance");
    const size_t tip_layers = branch_radius / layer_height; //The number of layers to be shrinking the circle to create a tip. This produces a 45 degree angle.
    const double diameter_angle_scale_factor = sin(storage.getSettingInAngleRadians("support_tree_branch_diameter_angle")) * layer_height / branch_radius; //Scale factor per layer to produce the desired angle.
    constexpr bool include_helper_parts = false;
    model_collision_tips.push_back(storage.getLayerOutlines(0, include_helper_parts).offset(xy_distance));
    model_collision_base.push_back(storage.getLayerOutlines(0, include_helper_parts).offset(xy_distance));
    //TODO: If allowing support to rest on model, these need to be just the model outlines.
    for (size_t layer_nr = 1; layer_nr < storage.print_layer_count; layer_nr ++)
    {
        //Generate an area above the current layer where you'd still collide with the current layer if you were to move with at most maximum_move_distance.
        model_collision_tips.push_back(model_collision_tips[layer_nr - 1].offset(-maximum_move_distance)); //Inset previous layer with maximum_move_distance to allow some movement.
        model_collision_base.push_back(model_collision_base[layer_nr - 1].offset(-maximum_move_distance));
        model_collision_tips[layer_nr] = model_collision_tips[layer_nr].unionPolygons(storage.getLayerOutlines(layer_nr, include_helper_parts).offset(xy_distance)); //Add current layer's collision to that.
        const coord_t branch_radius_this_layer = branch_radius * (1 + (double)(storage.support.supportLayers.size() - tip_layers - layer_nr) * diameter_angle_scale_factor); //Highest possible branch radius in this layer.
        model_collision_base[layer_nr] = model_collision_base[layer_nr].unionPolygons(storage.getLayerOutlines(layer_nr, include_helper_parts).offset(xy_distance + branch_radius_this_layer));
    }

    //Use Minimum Spanning Tree to connect the points on each layer and move them while dropping them down.
    const coord_t line_width = storage.getSettingInMicrons("support_line_width");
    for (size_t layer_nr = contact_points.size() - 1; layer_nr > 0; layer_nr--) //Skip layer 0, since we can't drop down the vertices there.
    {
        MinimumSpanningTree mst(contact_points[layer_nr]);
        for (Point vertex : contact_points[layer_nr])
        {
            const Node node = contact_nodes[layer_nr][vertex];
            Point next_layer_vertex = vertex;
            std::vector<Point> neighbours = mst.adjacentNodes(vertex);
            if (!neighbours.empty()) //Need to move towards the neighbours.
            {
                Point sum_direction(0, 0);
                for (Point neighbour : neighbours)
                {
                    sum_direction += neighbour - vertex;
                }
                Point motion = normal(sum_direction, maximum_move_distance);
                if (neighbours.size() == 1 && vSize2(sum_direction) < maximum_move_distance * maximum_move_distance)
                {
                    if (mst.adjacentNodes(neighbours[0]).size() == 1) //We just have two nodes left!
                    {
                        next_layer_vertex += motion / 2;
                    }
                    else //This is a leaf that's about to collapse. Leave it out on the next layer.
                    {
                        contact_nodes[layer_nr - 1][neighbours[0]].distance_to_top = std::max(contact_nodes[layer_nr - 1][neighbours[0]].distance_to_top, node.distance_to_top);
                        continue;
                    }
                }
                else
                {
                    next_layer_vertex += motion;
                }
            }
            //Times sqrt(2) to allow for diagonal movements. It might not support well in theory but it works all right in practice, since they're corners.
            if (node.distance_to_top < tip_layers)
            {
                PolygonUtils::moveOutside(model_collision_tips[layer_nr], next_layer_vertex, branch_radius * SQRT_2, maximum_move_distance * maximum_move_distance); //Avoid collision.
            }
            else
            {
                PolygonUtils::moveOutside(model_collision_base[layer_nr], next_layer_vertex, maximum_move_distance * SQRT_2, maximum_move_distance * maximum_move_distance);
            }
            contact_points[layer_nr - 1].insert(next_layer_vertex);
            contact_nodes[layer_nr - 1][next_layer_vertex].distance_to_top = node.distance_to_top + 1;
            contact_nodes[layer_nr - 1][next_layer_vertex].skin_direction = node.skin_direction;
        }
    }

    const unsigned int wall_count = storage.getSettingAsCount("support_tree_wall_count");
    Polygon branch_circle; //Pre-generate a circle with correct diameter so that we don't have to recompute those (co)sines every time.
    for (unsigned int i = 0; i < CIRCLE_RESOLUTION; i++)
    {
        const double angle = (double)i / CIRCLE_RESOLUTION * 2 * M_PI; //In radians.
        branch_circle.emplace_back(cos(angle) * branch_radius, sin(angle) * branch_radius);
    }
    const coord_t circle_side_length = 2 * branch_radius * sin(M_PI / CIRCLE_RESOLUTION); //Side length of a regular polygon.
    for (size_t layer_nr = 0; layer_nr < contact_points.size(); layer_nr++)
    {
        Polygons support_layer;

        for (const Point point : contact_points[layer_nr])
        {
            const Node& node = contact_nodes[layer_nr][point];
            Polygon circle;
            const double scale = (double)node.distance_to_top / tip_layers;
            for (Point corner : branch_circle)
            {
                if (node.distance_to_top < tip_layers) //We're in the tip.
                {
                    if (node.skin_direction)
                    {
                        corner = Point(corner.X * (0.5 + scale / 2) + corner.Y * (0.5 - scale / 2), corner.X * (0.5 - scale / 2) + corner.Y * (0.5 + scale / 2));
                    }
                    else
                    {
                        corner = Point(corner.X * (0.5 + scale / 2) - corner.Y * (0.5 - scale / 2), corner.X * (-0.5 + scale / 2) + corner.Y * (0.5 + scale / 2));
                    }
                }
                else
                {
                    corner *= 1 + (double)(node.distance_to_top - tip_layers) * diameter_angle_scale_factor;
                }
                circle.add(point + corner);
            }
            support_layer.add(circle);
        }
        support_layer = support_layer.unionPolygons();
        //We smooth this support as much as possible without altering single circles. So we remove any line less than the side length of those circles.
        const double diameter_angle_scale_factor_this_layer = (double)(storage.support.supportLayers.size() - layer_nr - tip_layers) * diameter_angle_scale_factor; //Maximum scale factor.
        support_layer.simplify(circle_side_length * (1 + diameter_angle_scale_factor_this_layer), line_width >> 2); //Deviate at most a quarter of a line so that the lines still stack properly.
        for (PolygonRef part : support_layer) //Convert every part into a PolygonsPart for the support.
        {
            PolygonsPart outline;
            outline.add(part);
            storage.support.supportLayers[layer_nr].support_infill_parts.emplace_back(outline, line_width, wall_count);
        }
        if (!storage.support.supportLayers[layer_nr].support_infill_parts.empty())
        {
            storage.support.layer_nr_max_filled_layer = layer_nr;
        }
    }

    storage.support.generated = true;
}

void TreeSupport::generateContactPoints(const SliceMeshStorage& mesh, std::vector<std::unordered_set<Point>>& contact_points, std::vector<std::unordered_map<Point, TreeSupport::Node>>& contact_nodes)
{
    const coord_t layer_height = mesh.getSettingInMicrons("layer_height");
    const coord_t z_distance_top = mesh.getSettingInMicrons("support_top_distance");
    const size_t z_distance_top_layers = std::max(0U, round_up_divide(z_distance_top, layer_height)) + 1; //Support must always be 1 layer below overhang.
    for (size_t layer_nr = 0; layer_nr < mesh.overhang_areas.size() - z_distance_top_layers; layer_nr++)
    {
        const Polygons& overhang = mesh.overhang_areas[layer_nr + z_distance_top_layers];
        if (overhang.empty())
        {
            continue;
        }

        //First generate a lot of points in a grid pattern.
        const Polygons outside_polygons = overhang.getOutsidePolygons();
        const AABB bounding_box(outside_polygons); //To know how far we should generate points.
        const coord_t point_spread = mesh.getSettingInMicrons("support_tree_branch_distance");

        //We want to create the grid pattern at an angle, so compute the bounding box required to cover that angle.
        constexpr double rotate_angle = 22.0 / 180.0 * M_PI; //Rotation of 22 degrees provides better support of diagonal lines.
        const Point bounding_box_size = bounding_box.max - bounding_box.min;
        AABB rotated_bounding_box;
        rotated_bounding_box.include(Point(0, 0));
        rotated_bounding_box.include(rotate(bounding_box_size, -rotate_angle));
        rotated_bounding_box.include(rotate(Point(0, bounding_box_size.Y), -rotate_angle));
        rotated_bounding_box.include(rotate(Point(bounding_box_size.X, 0), -rotate_angle));
        AABB unrotated_bounding_box;
        unrotated_bounding_box.include(rotate(rotated_bounding_box.min, rotate_angle));
        unrotated_bounding_box.include(rotate(rotated_bounding_box.max, rotate_angle));
        unrotated_bounding_box.include(rotate(Point(rotated_bounding_box.min.X, rotated_bounding_box.max.Y), rotate_angle));
        unrotated_bounding_box.include(rotate(Point(rotated_bounding_box.max.X, rotated_bounding_box.min.Y), rotate_angle));

        for (const ConstPolygonRef overhang_part : outside_polygons)
        {
            bool added = false; //Did we add a point this way?
            for (coord_t x = unrotated_bounding_box.min.X; x <= unrotated_bounding_box.max.X; x += point_spread)
            {
                for (coord_t y = unrotated_bounding_box.min.Y; y <= unrotated_bounding_box.max.Y; y += point_spread)
                {
                    Point candidate = rotate(Point(x, y), rotate_angle) + bounding_box.min;
                    constexpr bool border_is_inside = true;
                    if (overhang_part.inside(candidate, border_is_inside))
                    {
                        contact_points[layer_nr].insert(candidate);
                        contact_nodes[layer_nr][candidate] = Node();
                        contact_nodes[layer_nr][candidate].skin_direction = (layer_nr + z_distance_top_layers) % 2;
                        added = true;
                    }
                }
            }
            if (!added) //If we didn't add any points due to bad luck, we want to add one anyway such that loose parts are also supported.
            {
                Point candidate = bounding_box.getMiddle();
                PolygonUtils::moveInside(overhang_part, candidate);
                contact_points[layer_nr].insert(candidate);
                contact_nodes[layer_nr][candidate] = Node();
                contact_nodes[layer_nr][candidate].skin_direction = layer_nr % 2;
            }
        }
    }
}

}<commit_msg>Don't start from scale 0<commit_after>//Copyright (c) 2017 Ultimaker B.V.
//CuraEngine is released under the terms of the AGPLv3 or higher.

#include "utils/intpoint.h" //To normalize vectors.
#include "utils/math.h" //For round_up_divide and PI.
#include "utils/MinimumSpanningTree.h" //For connecting the correct nodes together to form an efficient tree.
#include "utils/polygonUtils.h" //For moveInside.

#include "TreeSupport.h"

#define SQRT_2 1.4142135623730950488 //Square root of 2.
#define CIRCLE_RESOLUTION 10 //The number of vertices in each circle.

namespace cura
{

TreeSupport::TreeSupport()
{
}

void TreeSupport::generateSupportAreas(SliceDataStorage& storage)
{
    std::vector<std::unordered_set<Point>> contact_points;
    std::vector<std::unordered_map<Point, Node>> contact_nodes;
    contact_points.reserve(storage.support.supportLayers.size());
    contact_nodes.reserve(storage.support.supportLayers.size());
    for (size_t layer_nr = 0; layer_nr < storage.support.supportLayers.size(); layer_nr++) //Generate empty layers to store the points in.
    {
        contact_points.emplace_back();
        contact_nodes.emplace_back();
    }
    for (SliceMeshStorage& mesh : storage.meshes)
    {
        if (!mesh.getSettingBoolean("support_tree_enable"))
        {
            return;
        }
        generateContactPoints(mesh, contact_points, contact_nodes);
    }

    //Generate areas that have to be avoided.
    const coord_t layer_height = storage.getSettingInMicrons("layer_height");
    const double angle = storage.getSettingInAngleRadians("support_tree_angle");
    const coord_t maximum_move_distance = tan(angle) * layer_height;
    std::vector<Polygons> model_collision_tips; //Areas that have to be avoided by the tips of the branches.
    std::vector<Polygons> model_collision_base; //Areas that have to be avoided by the normal parts of the branches.
    const coord_t branch_radius = storage.getSettingInMicrons("support_tree_branch_diameter") >> 1;
    const coord_t xy_distance = storage.getSettingInMicrons("support_xy_distance");
    const size_t tip_layers = branch_radius / layer_height; //The number of layers to be shrinking the circle to create a tip. This produces a 45 degree angle.
    const double diameter_angle_scale_factor = sin(storage.getSettingInAngleRadians("support_tree_branch_diameter_angle")) * layer_height / branch_radius; //Scale factor per layer to produce the desired angle.
    constexpr bool include_helper_parts = false;
    model_collision_tips.push_back(storage.getLayerOutlines(0, include_helper_parts).offset(xy_distance));
    model_collision_base.push_back(storage.getLayerOutlines(0, include_helper_parts).offset(xy_distance));
    //TODO: If allowing support to rest on model, these need to be just the model outlines.
    for (size_t layer_nr = 1; layer_nr < storage.print_layer_count; layer_nr ++)
    {
        //Generate an area above the current layer where you'd still collide with the current layer if you were to move with at most maximum_move_distance.
        model_collision_tips.push_back(model_collision_tips[layer_nr - 1].offset(-maximum_move_distance)); //Inset previous layer with maximum_move_distance to allow some movement.
        model_collision_base.push_back(model_collision_base[layer_nr - 1].offset(-maximum_move_distance));
        model_collision_tips[layer_nr] = model_collision_tips[layer_nr].unionPolygons(storage.getLayerOutlines(layer_nr, include_helper_parts).offset(xy_distance)); //Add current layer's collision to that.
        const coord_t branch_radius_this_layer = branch_radius * (1 + (double)(storage.support.supportLayers.size() - tip_layers - layer_nr) * diameter_angle_scale_factor); //Highest possible branch radius in this layer.
        model_collision_base[layer_nr] = model_collision_base[layer_nr].unionPolygons(storage.getLayerOutlines(layer_nr, include_helper_parts).offset(xy_distance + branch_radius_this_layer));
    }

    //Use Minimum Spanning Tree to connect the points on each layer and move them while dropping them down.
    const coord_t line_width = storage.getSettingInMicrons("support_line_width");
    for (size_t layer_nr = contact_points.size() - 1; layer_nr > 0; layer_nr--) //Skip layer 0, since we can't drop down the vertices there.
    {
        MinimumSpanningTree mst(contact_points[layer_nr]);
        for (Point vertex : contact_points[layer_nr])
        {
            const Node node = contact_nodes[layer_nr][vertex];
            Point next_layer_vertex = vertex;
            std::vector<Point> neighbours = mst.adjacentNodes(vertex);
            if (!neighbours.empty()) //Need to move towards the neighbours.
            {
                Point sum_direction(0, 0);
                for (Point neighbour : neighbours)
                {
                    sum_direction += neighbour - vertex;
                }
                Point motion = normal(sum_direction, maximum_move_distance);
                if (neighbours.size() == 1 && vSize2(sum_direction) < maximum_move_distance * maximum_move_distance)
                {
                    if (mst.adjacentNodes(neighbours[0]).size() == 1) //We just have two nodes left!
                    {
                        next_layer_vertex += motion / 2;
                    }
                    else //This is a leaf that's about to collapse. Leave it out on the next layer.
                    {
                        contact_nodes[layer_nr - 1][neighbours[0]].distance_to_top = std::max(contact_nodes[layer_nr - 1][neighbours[0]].distance_to_top, node.distance_to_top);
                        continue;
                    }
                }
                else
                {
                    next_layer_vertex += motion;
                }
            }
            //Times sqrt(2) to allow for diagonal movements. It might not support well in theory but it works all right in practice, since they're corners.
            if (node.distance_to_top < tip_layers)
            {
                PolygonUtils::moveOutside(model_collision_tips[layer_nr], next_layer_vertex, branch_radius * SQRT_2, maximum_move_distance * maximum_move_distance); //Avoid collision.
            }
            else
            {
                PolygonUtils::moveOutside(model_collision_base[layer_nr], next_layer_vertex, maximum_move_distance * SQRT_2, maximum_move_distance * maximum_move_distance);
            }
            contact_points[layer_nr - 1].insert(next_layer_vertex);
            contact_nodes[layer_nr - 1][next_layer_vertex].distance_to_top = node.distance_to_top + 1;
            contact_nodes[layer_nr - 1][next_layer_vertex].skin_direction = node.skin_direction;
        }
    }

    const unsigned int wall_count = storage.getSettingAsCount("support_tree_wall_count");
    Polygon branch_circle; //Pre-generate a circle with correct diameter so that we don't have to recompute those (co)sines every time.
    for (unsigned int i = 0; i < CIRCLE_RESOLUTION; i++)
    {
        const double angle = (double)i / CIRCLE_RESOLUTION * 2 * M_PI; //In radians.
        branch_circle.emplace_back(cos(angle) * branch_radius, sin(angle) * branch_radius);
    }
    const coord_t circle_side_length = 2 * branch_radius * sin(M_PI / CIRCLE_RESOLUTION); //Side length of a regular polygon.
    for (size_t layer_nr = 0; layer_nr < contact_points.size(); layer_nr++)
    {
        Polygons support_layer;

        for (const Point point : contact_points[layer_nr])
        {
            const Node& node = contact_nodes[layer_nr][point];
            Polygon circle;
            const double scale = (double)(node.distance_to_top + 1) / tip_layers;
            for (Point corner : branch_circle)
            {
                if (node.distance_to_top < tip_layers) //We're in the tip.
                {
                    if (node.skin_direction)
                    {
                        corner = Point(corner.X * (0.5 + scale / 2) + corner.Y * (0.5 - scale / 2), corner.X * (0.5 - scale / 2) + corner.Y * (0.5 + scale / 2));
                    }
                    else
                    {
                        corner = Point(corner.X * (0.5 + scale / 2) - corner.Y * (0.5 - scale / 2), corner.X * (-0.5 + scale / 2) + corner.Y * (0.5 + scale / 2));
                    }
                }
                else
                {
                    corner *= 1 + (double)(node.distance_to_top - tip_layers) * diameter_angle_scale_factor;
                }
                circle.add(point + corner);
            }
            support_layer.add(circle);
        }
        support_layer = support_layer.unionPolygons();
        //We smooth this support as much as possible without altering single circles. So we remove any line less than the side length of those circles.
        const double diameter_angle_scale_factor_this_layer = (double)(storage.support.supportLayers.size() - layer_nr - tip_layers) * diameter_angle_scale_factor; //Maximum scale factor.
        support_layer.simplify(circle_side_length * (1 + diameter_angle_scale_factor_this_layer), line_width >> 2); //Deviate at most a quarter of a line so that the lines still stack properly.
        for (PolygonRef part : support_layer) //Convert every part into a PolygonsPart for the support.
        {
            PolygonsPart outline;
            outline.add(part);
            storage.support.supportLayers[layer_nr].support_infill_parts.emplace_back(outline, line_width, wall_count);
        }
        if (!storage.support.supportLayers[layer_nr].support_infill_parts.empty())
        {
            storage.support.layer_nr_max_filled_layer = layer_nr;
        }
    }

    storage.support.generated = true;
}

void TreeSupport::generateContactPoints(const SliceMeshStorage& mesh, std::vector<std::unordered_set<Point>>& contact_points, std::vector<std::unordered_map<Point, TreeSupport::Node>>& contact_nodes)
{
    const coord_t layer_height = mesh.getSettingInMicrons("layer_height");
    const coord_t z_distance_top = mesh.getSettingInMicrons("support_top_distance");
    const size_t z_distance_top_layers = std::max(0U, round_up_divide(z_distance_top, layer_height)) + 1; //Support must always be 1 layer below overhang.
    for (size_t layer_nr = 0; layer_nr < mesh.overhang_areas.size() - z_distance_top_layers; layer_nr++)
    {
        const Polygons& overhang = mesh.overhang_areas[layer_nr + z_distance_top_layers];
        if (overhang.empty())
        {
            continue;
        }

        //First generate a lot of points in a grid pattern.
        const Polygons outside_polygons = overhang.getOutsidePolygons();
        const AABB bounding_box(outside_polygons); //To know how far we should generate points.
        const coord_t point_spread = mesh.getSettingInMicrons("support_tree_branch_distance");

        //We want to create the grid pattern at an angle, so compute the bounding box required to cover that angle.
        constexpr double rotate_angle = 22.0 / 180.0 * M_PI; //Rotation of 22 degrees provides better support of diagonal lines.
        const Point bounding_box_size = bounding_box.max - bounding_box.min;
        AABB rotated_bounding_box;
        rotated_bounding_box.include(Point(0, 0));
        rotated_bounding_box.include(rotate(bounding_box_size, -rotate_angle));
        rotated_bounding_box.include(rotate(Point(0, bounding_box_size.Y), -rotate_angle));
        rotated_bounding_box.include(rotate(Point(bounding_box_size.X, 0), -rotate_angle));
        AABB unrotated_bounding_box;
        unrotated_bounding_box.include(rotate(rotated_bounding_box.min, rotate_angle));
        unrotated_bounding_box.include(rotate(rotated_bounding_box.max, rotate_angle));
        unrotated_bounding_box.include(rotate(Point(rotated_bounding_box.min.X, rotated_bounding_box.max.Y), rotate_angle));
        unrotated_bounding_box.include(rotate(Point(rotated_bounding_box.max.X, rotated_bounding_box.min.Y), rotate_angle));

        for (const ConstPolygonRef overhang_part : outside_polygons)
        {
            bool added = false; //Did we add a point this way?
            for (coord_t x = unrotated_bounding_box.min.X; x <= unrotated_bounding_box.max.X; x += point_spread)
            {
                for (coord_t y = unrotated_bounding_box.min.Y; y <= unrotated_bounding_box.max.Y; y += point_spread)
                {
                    Point candidate = rotate(Point(x, y), rotate_angle) + bounding_box.min;
                    constexpr bool border_is_inside = true;
                    if (overhang_part.inside(candidate, border_is_inside))
                    {
                        contact_points[layer_nr].insert(candidate);
                        contact_nodes[layer_nr][candidate] = Node();
                        contact_nodes[layer_nr][candidate].skin_direction = (layer_nr + z_distance_top_layers) % 2;
                        added = true;
                    }
                }
            }
            if (!added) //If we didn't add any points due to bad luck, we want to add one anyway such that loose parts are also supported.
            {
                Point candidate = bounding_box.getMiddle();
                PolygonUtils::moveInside(overhang_part, candidate);
                contact_points[layer_nr].insert(candidate);
                contact_nodes[layer_nr][candidate] = Node();
                contact_nodes[layer_nr][candidate].skin_direction = layer_nr % 2;
            }
        }
    }
}

}<|endoftext|>