<commit_before>/** \copyright
 * Copyright (c) 2012, Stuart W Baker
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are  permitted provided that the following conditions are met:
 *
 *  - Redistributions of source code must retain the above copyright notice,
 *    this list of conditions and the following disclaimer.
 *
 *  - Redistributions in binary form must reproduce the above copyright notice,
 *    this list of conditions and the following disclaimer in the documentation
 *    and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 *
 * \file HwInit.cxx
 * This file represents the hardware initialization for the TI Tiva MCU.
 *
 * @author Stuart W. Baker
 * @date 5 January 2013
 */

#include <new>
#include <cstdint>

#include "inc/hw_types.h"
#include "inc/hw_memmap.h"
#include "inc/hw_ints.h"
#include "driverlib/rom.h"
#include "driverlib/rom_map.h"
#include "driverlib/sysctl.h"
#include "driverlib/gpio.h"
#include "driverlib/timer.h"
#include "driverlib/interrupt.h"
#include "driverlib/pin_map.h"
#include "os/OS.hxx"
#include "TivaDev.hxx"
#include "hardware.hxx"
#include "DccHardware.hxx"
#include "TivaDCC.hxx"

struct Debug {
  // High between start_cutout and end_cutout from the TivaRailcom driver.
  typedef DummyPin RailcomDriverCutout;
  // Flips every time an uart byte is received error.
  typedef DummyPin RailcomError;
  // Flips every time an 'E0' byte is received in the railcom driver.
  typedef DummyPin RailcomE0;
};
#include "TivaRailcom.hxx"

/** override stdin */
const char *STDIN_DEVICE = "/dev/ser0";

/** override stdout */
const char *STDOUT_DEVICE = "/dev/ser0";

/** override stderr */
const char *STDERR_DEVICE = "/dev/ser0";

/** USB Device CDC serial driver instance */
static TivaCdc cdc0("/dev/serUSB0", INT_RESOLVE(INT_USB0_, 0));

/** UART 0 serial driver instance */
static TivaUart uart0("/dev/ser0", UART0_BASE, INT_RESOLVE(INT_UART0_, 0));

/** CAN 0 CAN driver instance */
static TivaCan can0("/dev/can0", CAN0_BASE, INT_RESOLVE(INT_CAN0_, 0));

// Bit storing whether our dcc output is enabled or not.
static bool g_dcc_on = false;

TivaRailcomDriver<RailcomDefs> railcom_driver("/dev/railcom");
TivaDCC<DccHwDefs> dcc_hw("/dev/mainline", &railcom_driver);

extern "C" {

void hw_set_to_safe(void)
{
    dcc_hw.disable_output();
}

void timer1a_interrupt_handler(void)
{
    dcc_hw.interrupt_handler();
}

void timer0a_interrupt_handler(void)
{
  dcc_hw.os_interrupt_handler();
}

void uart1_interrupt_handler(void)
{
  railcom_driver.os_interrupt_handler();
}

/** Blink LED */
uint32_t blinker_pattern = 0;
static uint32_t rest_pattern = 0;

void resetblink(uint32_t pattern)
{
    blinker_pattern = pattern;
    /* make a timer event trigger immediately */
}

void setblink(uint32_t pattern)
{
    resetblink(pattern);
}

void timer5a_interrupt_handler(void)
{
    //
    // Clear the timer interrupt.
    //
    MAP_TimerIntClear(TIMER5_BASE, TIMER_TIMA_TIMEOUT);
    // Set output LED.
    MAP_GPIOPinWrite(GPIO_PORTF_BASE, GPIO_PIN_1,
                     (rest_pattern & 1) ? GPIO_PIN_1 : 0);
    // Shift and maybe reset pattern.
    rest_pattern >>= 1;
    if (!rest_pattern)
        rest_pattern = blinker_pattern;
}

void diewith(uint32_t pattern)
{
    hw_set_to_safe();
    vPortClearInterruptMask(0x20);
    asm("cpsie i\n");

    resetblink(pattern);
    while (1)
        ;
}

/** Configures a GPIO pin to directly drive a LED (with 8mA output drive). */
void set_gpio_led(uint32_t port, uint32_t pin) {
    MAP_GPIOPinWrite(port, pin, 0xff);
    MAP_GPIOPinTypeGPIOOutput(port, pin);
    MAP_GPIOPadConfigSet(port, pin, GPIO_STRENGTH_8MA_SC, GPIO_PIN_TYPE_STD);
    MAP_GPIOPinWrite(port, pin, 0xff);
}

/** Configures a GPIO pin to directly drive a LED (with 2mA output drive). */
void set_gpio_drive_low(uint32_t port, uint32_t pin) {
    MAP_GPIOPinWrite(port, pin, 0);
    MAP_GPIOPinTypeGPIOOutput(port, pin);
    MAP_GPIOPadConfigSet(port, pin, GPIO_STRENGTH_2MA, GPIO_PIN_TYPE_STD);
    MAP_GPIOPinWrite(port, pin, 0);
}

/** Configures a GPIO pin to directly drive a LED (with 2mA output drive). */
void set_gpio_drive_high(uint32_t port, uint32_t pin) {
    MAP_GPIOPinWrite(port, pin, 0xff);
    MAP_GPIOPinTypeGPIOOutput(port, pin);
    MAP_GPIOPadConfigSet(port, pin, GPIO_STRENGTH_2MA, GPIO_PIN_TYPE_STD);
    MAP_GPIOPinWrite(port, pin, 0xff);
}

/** Configures a gpio pin for input with external pullup. */
void set_gpio_extinput(uint32_t port, uint32_t pin) {
    MAP_GPIOPinWrite(port, pin, 0);
    MAP_GPIOPinTypeGPIOInput(port, pin);
    MAP_GPIOPadConfigSet(port, pin, GPIO_STRENGTH_2MA, GPIO_PIN_TYPE_STD);
}

/** Configures a gpio pin for input with internal pullup. */
void set_gpio_puinput(uint32_t port, uint32_t pin) {
    MAP_GPIOPinWrite(port, pin, 0);
    MAP_GPIOPinTypeGPIOInput(port, pin);
    MAP_GPIOPadConfigSet(port, pin, GPIO_STRENGTH_2MA, GPIO_PIN_TYPE_STD_WPU);
}

void enable_dcc() {
    g_dcc_on = true;
    MAP_GPIOPinWrite(LED_BLUE, 0xff);
    dcc_hw.enable_output();
}

void disable_dcc() {
    dcc_hw.disable_output();
    g_dcc_on = false;
    MAP_GPIOPinWrite(LED_BLUE, 0);
}

bool query_dcc() {
  return g_dcc_on;
}

/** Initialize the processor hardware.
 */
void hw_preinit(void)
{
    /* Globally disables interrupts until the FreeRTOS scheduler is up. */
    asm("cpsid i\n");

    MAP_SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOB);
    MAP_SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOD);
    MAP_SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOF);

    // Sets DCC hardware to safe state.
    // These pins are parallel-connected to the outputs.
    set_gpio_extinput(GPIO_PORTD_BASE, GPIO_PIN_0 | GPIO_PIN_1);
    /* Initialize the DCC Timers and GPIO outputs */
    dcc_hw.hw_init();
    disable_dcc();

    /* Setup the system clock. */
    MAP_SysCtlClockSet(SYSCTL_SYSDIV_2_5 | SYSCTL_USE_PLL | SYSCTL_OSC_MAIN |
                       SYSCTL_XTAL_16MHZ);

    /* Red LED pin initialization */
    MAP_SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOF);
    set_gpio_led(LED_RED);

    /* Blinker timer initialization. */
    MAP_SysCtlPeripheralEnable(SYSCTL_PERIPH_TIMER5);
    MAP_TimerConfigure(TIMER5_BASE, TIMER_CFG_PERIODIC);
    MAP_TimerLoadSet(TIMER5_BASE, TIMER_A, MAP_SysCtlClockGet() / 8);
    MAP_IntEnable(INT_TIMER5A);

    /* This interrupt should hit even during kernel operations. */
    MAP_IntPrioritySet(INT_TIMER5A, 0);
    MAP_TimerIntEnable(TIMER5_BASE, TIMER_TIMA_TIMEOUT);
    MAP_TimerEnable(TIMER5_BASE, TIMER_A);

    /* UART0 pin initialization */
    MAP_SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOA);
    MAP_GPIOPinConfigure(GPIO_PA0_U0RX);
    MAP_GPIOPinConfigure(GPIO_PA1_U0TX);
    MAP_GPIOPinTypeUART(GPIO_PORTA_BASE, GPIO_PIN_0 | GPIO_PIN_1);

    /* USB0 pin initialization */
    MAP_SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOD);
    MAP_GPIOPinTypeUSBAnalog(GPIO_PORTD_BASE, GPIO_PIN_5 | GPIO_PIN_4);

    /* CAN pin initialization */
    MAP_SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOE);
    MAP_GPIOPinConfigure(GPIO_PE4_CAN0RX);
    MAP_GPIOPinConfigure(GPIO_PE5_CAN0TX);
    MAP_GPIOPinTypeCAN(GPIO_PORTE_BASE, GPIO_PIN_4 | GPIO_PIN_5);

    /* Blue LED pin initialization */
    set_gpio_led(LED_BLUE);
    set_gpio_led(LED_GREEN);
    MAP_GPIOPinWrite(LED_GREEN, 0);
    MAP_GPIOPinWrite(LED_RED, 0);
    MAP_GPIOPinWrite(LED_BLUE, 0);

    /* USB interrupt priority */
    MAP_IntPrioritySet(INT_USB0, 0xff); // USB interrupt low priority

    MAP_SysCtlPeripheralEnable(SYSCTL_PERIPH_TIMER0);
    MAP_SysCtlPeripheralEnable(SYSCTL_PERIPH_TIMER1);
}

}  // extern "C"
<commit_msg>Fixes broken build when debug pins changed.<commit_after>/** \copyright
 * Copyright (c) 2012, Stuart W Baker
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are  permitted provided that the following conditions are met:
 *
 *  - Redistributions of source code must retain the above copyright notice,
 *    this list of conditions and the following disclaimer.
 *
 *  - Redistributions in binary form must reproduce the above copyright notice,
 *    this list of conditions and the following disclaimer in the documentation
 *    and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 *
 * \file HwInit.cxx
 * This file represents the hardware initialization for the TI Tiva MCU.
 *
 * @author Stuart W. Baker
 * @date 5 January 2013
 */

#include <new>
#include <cstdint>

#include "inc/hw_types.h"
#include "inc/hw_memmap.h"
#include "inc/hw_ints.h"
#include "driverlib/rom.h"
#include "driverlib/rom_map.h"
#include "driverlib/sysctl.h"
#include "driverlib/gpio.h"
#include "driverlib/timer.h"
#include "driverlib/interrupt.h"
#include "driverlib/pin_map.h"
#include "os/OS.hxx"
#include "TivaDev.hxx"
#include "hardware.hxx"
#include "DccHardware.hxx"
#include "TivaDCC.hxx"

struct Debug {
  // High between start_cutout and end_cutout from the TivaRailcom driver.
  typedef DummyPin RailcomDriverCutout;
  // Flips every time an uart byte is received error.
  typedef DummyPin RailcomError;
  // Flips every time an 'E0' byte is received in the railcom driver.
  typedef DummyPin RailcomE0;
  typedef DummyPin RailcomDataReceived;
  typedef DummyPin RailcomAnyData;
  typedef DummyPin RailcomPackets;
};
#include "TivaRailcom.hxx"

/** override stdin */
const char *STDIN_DEVICE = "/dev/ser0";

/** override stdout */
const char *STDOUT_DEVICE = "/dev/ser0";

/** override stderr */
const char *STDERR_DEVICE = "/dev/ser0";

/** USB Device CDC serial driver instance */
static TivaCdc cdc0("/dev/serUSB0", INT_RESOLVE(INT_USB0_, 0));

/** UART 0 serial driver instance */
static TivaUart uart0("/dev/ser0", UART0_BASE, INT_RESOLVE(INT_UART0_, 0));

/** CAN 0 CAN driver instance */
static TivaCan can0("/dev/can0", CAN0_BASE, INT_RESOLVE(INT_CAN0_, 0));

// Bit storing whether our dcc output is enabled or not.
static bool g_dcc_on = false;

TivaRailcomDriver<RailcomDefs> railcom_driver("/dev/railcom");
TivaDCC<DccHwDefs> dcc_hw("/dev/mainline", &railcom_driver);

extern "C" {

void hw_set_to_safe(void)
{
    dcc_hw.disable_output();
}

void timer1a_interrupt_handler(void)
{
    dcc_hw.interrupt_handler();
}

void timer0a_interrupt_handler(void)
{
  dcc_hw.os_interrupt_handler();
}

void uart1_interrupt_handler(void)
{
  railcom_driver.os_interrupt_handler();
}

/** Blink LED */
uint32_t blinker_pattern = 0;
static uint32_t rest_pattern = 0;

void resetblink(uint32_t pattern)
{
    blinker_pattern = pattern;
    /* make a timer event trigger immediately */
}

void setblink(uint32_t pattern)
{
    resetblink(pattern);
}

void timer5a_interrupt_handler(void)
{
    //
    // Clear the timer interrupt.
    //
    MAP_TimerIntClear(TIMER5_BASE, TIMER_TIMA_TIMEOUT);
    // Set output LED.
    MAP_GPIOPinWrite(GPIO_PORTF_BASE, GPIO_PIN_1,
                     (rest_pattern & 1) ? GPIO_PIN_1 : 0);
    // Shift and maybe reset pattern.
    rest_pattern >>= 1;
    if (!rest_pattern)
        rest_pattern = blinker_pattern;
}

void diewith(uint32_t pattern)
{
    hw_set_to_safe();
    vPortClearInterruptMask(0x20);
    asm("cpsie i\n");

    resetblink(pattern);
    while (1)
        ;
}

/** Configures a GPIO pin to directly drive a LED (with 8mA output drive). */
void set_gpio_led(uint32_t port, uint32_t pin) {
    MAP_GPIOPinWrite(port, pin, 0xff);
    MAP_GPIOPinTypeGPIOOutput(port, pin);
    MAP_GPIOPadConfigSet(port, pin, GPIO_STRENGTH_8MA_SC, GPIO_PIN_TYPE_STD);
    MAP_GPIOPinWrite(port, pin, 0xff);
}

/** Configures a GPIO pin to directly drive a LED (with 2mA output drive). */
void set_gpio_drive_low(uint32_t port, uint32_t pin) {
    MAP_GPIOPinWrite(port, pin, 0);
    MAP_GPIOPinTypeGPIOOutput(port, pin);
    MAP_GPIOPadConfigSet(port, pin, GPIO_STRENGTH_2MA, GPIO_PIN_TYPE_STD);
    MAP_GPIOPinWrite(port, pin, 0);
}

/** Configures a GPIO pin to directly drive a LED (with 2mA output drive). */
void set_gpio_drive_high(uint32_t port, uint32_t pin) {
    MAP_GPIOPinWrite(port, pin, 0xff);
    MAP_GPIOPinTypeGPIOOutput(port, pin);
    MAP_GPIOPadConfigSet(port, pin, GPIO_STRENGTH_2MA, GPIO_PIN_TYPE_STD);
    MAP_GPIOPinWrite(port, pin, 0xff);
}

/** Configures a gpio pin for input with external pullup. */
void set_gpio_extinput(uint32_t port, uint32_t pin) {
    MAP_GPIOPinWrite(port, pin, 0);
    MAP_GPIOPinTypeGPIOInput(port, pin);
    MAP_GPIOPadConfigSet(port, pin, GPIO_STRENGTH_2MA, GPIO_PIN_TYPE_STD);
}

/** Configures a gpio pin for input with internal pullup. */
void set_gpio_puinput(uint32_t port, uint32_t pin) {
    MAP_GPIOPinWrite(port, pin, 0);
    MAP_GPIOPinTypeGPIOInput(port, pin);
    MAP_GPIOPadConfigSet(port, pin, GPIO_STRENGTH_2MA, GPIO_PIN_TYPE_STD_WPU);
}

void enable_dcc() {
    g_dcc_on = true;
    MAP_GPIOPinWrite(LED_BLUE, 0xff);
    dcc_hw.enable_output();
}

void disable_dcc() {
    dcc_hw.disable_output();
    g_dcc_on = false;
    MAP_GPIOPinWrite(LED_BLUE, 0);
}

bool query_dcc() {
  return g_dcc_on;
}

/** Initialize the processor hardware.
 */
void hw_preinit(void)
{
    /* Globally disables interrupts until the FreeRTOS scheduler is up. */
    asm("cpsid i\n");

    MAP_SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOB);
    MAP_SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOD);
    MAP_SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOF);

    // Sets DCC hardware to safe state.
    // These pins are parallel-connected to the outputs.
    set_gpio_extinput(GPIO_PORTD_BASE, GPIO_PIN_0 | GPIO_PIN_1);
    /* Initialize the DCC Timers and GPIO outputs */
    dcc_hw.hw_init();
    disable_dcc();

    /* Setup the system clock. */
    MAP_SysCtlClockSet(SYSCTL_SYSDIV_2_5 | SYSCTL_USE_PLL | SYSCTL_OSC_MAIN |
                       SYSCTL_XTAL_16MHZ);

    /* Red LED pin initialization */
    MAP_SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOF);
    set_gpio_led(LED_RED);

    /* Blinker timer initialization. */
    MAP_SysCtlPeripheralEnable(SYSCTL_PERIPH_TIMER5);
    MAP_TimerConfigure(TIMER5_BASE, TIMER_CFG_PERIODIC);
    MAP_TimerLoadSet(TIMER5_BASE, TIMER_A, MAP_SysCtlClockGet() / 8);
    MAP_IntEnable(INT_TIMER5A);

    /* This interrupt should hit even during kernel operations. */
    MAP_IntPrioritySet(INT_TIMER5A, 0);
    MAP_TimerIntEnable(TIMER5_BASE, TIMER_TIMA_TIMEOUT);
    MAP_TimerEnable(TIMER5_BASE, TIMER_A);

    /* UART0 pin initialization */
    MAP_SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOA);
    MAP_GPIOPinConfigure(GPIO_PA0_U0RX);
    MAP_GPIOPinConfigure(GPIO_PA1_U0TX);
    MAP_GPIOPinTypeUART(GPIO_PORTA_BASE, GPIO_PIN_0 | GPIO_PIN_1);

    /* USB0 pin initialization */
    MAP_SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOD);
    MAP_GPIOPinTypeUSBAnalog(GPIO_PORTD_BASE, GPIO_PIN_5 | GPIO_PIN_4);

    /* CAN pin initialization */
    MAP_SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOE);
    MAP_GPIOPinConfigure(GPIO_PE4_CAN0RX);
    MAP_GPIOPinConfigure(GPIO_PE5_CAN0TX);
    MAP_GPIOPinTypeCAN(GPIO_PORTE_BASE, GPIO_PIN_4 | GPIO_PIN_5);

    /* Blue LED pin initialization */
    set_gpio_led(LED_BLUE);
    set_gpio_led(LED_GREEN);
    MAP_GPIOPinWrite(LED_GREEN, 0);
    MAP_GPIOPinWrite(LED_RED, 0);
    MAP_GPIOPinWrite(LED_BLUE, 0);

    /* USB interrupt priority */
    MAP_IntPrioritySet(INT_USB0, 0xff); // USB interrupt low priority

    MAP_SysCtlPeripheralEnable(SYSCTL_PERIPH_TIMER0);
    MAP_SysCtlPeripheralEnable(SYSCTL_PERIPH_TIMER1);
}

}  // extern "C"
<|endoftext|>


<commit_before>/**
 * Copyright 2014-2017 Steven T Sell (ssell@vertexfragment.com)
 *
 * 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 "stdafx.h"
#include "D3D11GraphicsDriver.hpp"
#include "D3D11DynamicRegistration.hpp"

#include "Events/SceneObjectSelectedEvent.hpp"
#include "Events/SceneObjectFocusedEvent.hpp"
#include "Events/Events/MouseButtonInputEvent.hpp"

#include "Utilities/ColorPicker.hpp"

#include "Widgets/MainStatusBar.hpp"
#include "Widgets/MainWindow.hpp"
#include "Widgets/ContentFrame.hpp"
#include "Widgets/SceneFrame.hpp"
#include "Widgets/SceneTree.hpp"
#include "Widgets/Properties/Renderables/RenderableDisplay.hpp"

#include "Gizmos/Axis/AxisGizmo.hpp"
#include "Gizmos/Axis/AxisComponentGizmo.hpp"
#include "Graphics/Texture/NoiseTexture2D.hpp"
#include "Graphics/Texture/TextureSavers/TextureResourceSaver_PNG.hpp"
#include "Math/Noise/PerlinNoise.hpp"
#include "Math/Noise/SimplexNoise.hpp"
#include "Math/Noise/WaveletNoise.hpp"
#include "OcularEngine.hpp"
#include <regex>

//------------------------------------------------------------------------------------------

namespace Ocular
{
    namespace Editor
    {
        //----------------------------------------------------------------------------------
        // CONSTRUCTORS
        //----------------------------------------------------------------------------------

        Editor& Editor::get()
        {
            static Editor instance;
            return instance;
        }

        Editor::Editor()
            : AEventListener(),
              m_MainWindow(nullptr),
              m_EditorCamera(nullptr),
              m_SelectedObject(nullptr),
              m_FocusedObject(nullptr)
        {

        }

        Editor::~Editor()
        {
            delete m_MainWindow;
            delete m_QtApp;
        }

        //----------------------------------------------------------------------------------
        // PUBLIC METHODS
        //----------------------------------------------------------------------------------

        //----------------------------------------------------------------------------------
        // Core Lifetime Methods
        //----------------------------------------------------------------------------------

        bool Editor::initialize(int argc, char** argv)
        {
            bool result = false;

            m_QtApp = new QApplication(argc, argv);

            if(OcularEngine.initialize(new Ocular::Graphics::D3D11GraphicsDriver()))
            {
                OcularEvents->registerListener(this, Core::Priority::Low);

                m_MainWindow = new MainWindow();
                m_MainWindow->show();
                m_MainWindow->showMaximized();

                if(OcularGraphics->initialize())
                {
                    OcularResources->initialize();   // \todo really bad work around. trying to create default resources before driver is ready otherwise

                    if(setupEditorCamera())
                    {
                        setupAxis();
                        setupGizmos();

                        result = true;
                        OcularLogger->info("Successfully initialized ", OCULAR_VERSION);
                    }
                    else
                    {
                        OcularLogger->error("Failed to initialize Ocular Editor: failed to setup Editor cameras");
                    }
                }
                else
                {
                    OcularLogger->error("Failed to initialize Ocular Editor: failed to initialize Ocular Graphics system");
                }
            }
            else
            {
                OcularLogger->error("Failed to initialize Ocular Editor: failed to initialize Ocular Engine");
            }

            return result;
        }

        void Editor::shutdown()
        {
            OcularEngine.shutdown();
        }

        bool Editor::run()
        {
            bool result = false;

            Ocular::Graphics::TextureDescriptor descriptor;
            descriptor.width  = 512;
            descriptor.height = 512;

            std::shared_ptr<Ocular::Math::Noise::PerlinNoise> noise = std::make_shared<Ocular::Math::Noise::PerlinNoise>();
            noise->setOctaves(6);
            noise->setPersistence(0.5f);
            noise->setScale(0.01f);

            Ocular::Graphics::NoiseTexture2D* texture = new Ocular::Graphics::NoiseTexture2D(descriptor, noise);

            OcularEngine.ResourceManager()->saveResource(texture, Ocular::Core::File("TestOutput/PerlinNoise.png"));

            delete texture;
            texture = nullptr;

            if(OcularEngine.run())
            {
                m_MainWindow->update();
                m_QtApp->processEvents();

                result = true;
            }

            return result;
        }

        bool Editor::onEvent(std::shared_ptr<Core::AEvent> event)
        {
            if(event->isType<SceneObjectSelectedEvent>())
            {
                SceneObjectSelectedEvent* cast = dynamic_cast<SceneObjectSelectedEvent*>(event.get());
                m_SelectedObject = cast->object;
            }
            else if(event->isType<SceneObjectFocusedEvent>())
            {
                SceneObjectFocusedEvent* cast = dynamic_cast<SceneObjectFocusedEvent*>(event.get());
                m_FocusedObject = cast->object;
            }
            else if(event->isType<Core::MouseButtonInputEvent>())
            {
                Core::MouseButtonInputEvent* cast = dynamic_cast<Core::MouseButtonInputEvent*>(event.get());

                if(cast->button == Core::MouseButtons::Left)
                {
                    // Check if alt key is down (we assume a rotation around target if it is down)
                    if(!OcularInput->isKeyboardKeyDown(Core::KeyboardKeys::AltLeft))
                    {
                        performMousePick(cast->state);
                    }
                }
            }

            return true;
        }

        //----------------------------------------------------------------------------------
        // Primary Getters
        //----------------------------------------------------------------------------------

        MainWindow* Editor::getMainWindow() const
        {
            return m_MainWindow;
        }

        Core::Camera* Editor::getEditorCamera() const
        {
            return m_EditorCamera;
        }

        void Editor::setSelectedObject(Core::SceneObject* object, bool ignoreNormalObject, bool ignoreGizmoObject)
        {
            std::shared_ptr<Core::AEvent> event = nullptr;

            m_GizmoTranslate->setSelected(false);

            if(object)
            {
                m_GizmoTranslate->setActive(true);

                Gizmo* gizmo = dynamic_cast<Gizmo*>(object);

                if(gizmo)
                {
                    // If the selected object was a gizmo (or part of a gizmo), we can not
                    // set it as the selected object for obvious reasons.

                    // Instead we notify the gizmo that it has been selected (so that it can
                    // handle dragging, etc.) and maintain the current selected object.

                    if(!ignoreGizmoObject)
                    {
                        gizmo->setSelected(true);
                    }
                }
                else
                {
                    if(!ignoreNormalObject)
                    {
                        m_SelectedObject = object;

                        m_MainWindow->getContentFrame()->getSceneFrame()->getSceneTree()->selectObject(m_SelectedObject);
                        m_SelectedObject->addChild(m_GizmoTranslate, false);

                        event = std::make_shared<SceneObjectSelectedEvent>(m_SelectedObject);
                    }
                }
            }
            else
            {
                // Deselect

                m_GizmoTranslate->setActive(false);
                m_GizmoTranslate->setParent(nullptr, false);

                m_MainWindow->getContentFrame()->getSceneFrame()->getSceneTree()->selectObject(nullptr);

                event = std::make_shared<SceneObjectSelectedEvent>(nullptr);
            }

            if(event)
            {
                OcularEvents->queueEvent(event);
            }
        }

        Core::SceneObject* Editor::getSelectedObject() const
        {
            return m_SelectedObject;
        }

        Core::SceneObject* Editor::getFocusedObject() const
        {
            return m_FocusedObject;
        }

        //----------------------------------------------------------------------------------
        // Misc Methods
        //----------------------------------------------------------------------------------

        void Editor::setStatusNormal(std::string const& message)
        {
            auto statusBar = m_MainWindow->getMainStatusBar();

            if(statusBar)
            {
                statusBar->addWidget(new QLabel(message.c_str()));
            }
        }

        void Editor::setStatusPermanent(std::string const& message)
        {
            auto statusBar = m_MainWindow->getMainStatusBar();

            if(statusBar)
            {
                statusBar->setPermanentMessage(message.c_str());
            }
        }

        void Editor::setStatusTemporary(std::string const& message, uint32_t const lifetime)
        {
            auto statusBar = m_MainWindow->getMainStatusBar();

            if(statusBar)
            {
                statusBar->showMessage(message.c_str(), lifetime);
            }
        }

        void Editor::setStatusNormalProgress(std::string const& message, uint32_t const progress)
        {
            throw std::exception("implement me");
        }

        //----------------------------------------------------------------------------------
        // Widget Factories
        //----------------------------------------------------------------------------------

        PropertyWidget* Editor::createPropertyWidget(std::string const& displayName, std::string const& type)
        {
            PropertyWidget* result = m_PropertyWidgetFactory.createComponent(type);

            if(result)
            {
                result->setDisplayName(displayName);
            }

            return result;
        }

        Core::ComponentFactory<PropertyWidget>& Editor::getPropertyWidgetFactory()
        {
            return m_PropertyWidgetFactory;
        }

        PropertiesDisplayBox* Editor::createCustomDisplay(std::string const& type)
        {
            PropertiesDisplayBox* result = m_CustomDisplayFactory.createComponent(type);

            if(result)
            {
                result->setTitle(type.c_str());
            }

            return result;
        }

        Core::ComponentFactory<PropertiesDisplayBox>& Editor::getCustomDisplayFactory()
        {
            return m_CustomDisplayFactory;
        }

        RenderableDisplay* Editor::createRenderableDisplay(std::string const& type)
        {
            RenderableDisplay* result = m_RenderableDisplayFactory.createComponent(type);

            if(result)
            {
                result->setTitle(type.c_str());
            }

            return result;
        }

        Core::ComponentFactory<RenderableDisplay>& Editor::getRenderableDisplayFactory()
        {
            return m_RenderableDisplayFactory;
        }

        //----------------------------------------------------------------------------------
        // Static Methods
        //----------------------------------------------------------------------------------

        bool Editor::IsCommonName(std::string const& name)
        {
            bool result = false;

            static std::string CommonNames[8] =
            {
                "m_IsActive",
                "m_Name",
                "m_Position",
                "m_Rotation",
                "m_Scale",
                "m_Class",
                "m_IsStatic",
                "m_ForcedVisible"
            };

            for(auto commonName : CommonNames)
            {
                if(Utils::String::IsEqual(name, commonName))
                {
                    result = true;
                    break;
                }
            }

            return result;
        }

        std::string Editor::FormatName(std::string const& name)
        {
            std::string result = name;

            //------------------------------------------------------------
            // Remove any "m_"

            // Do regex instead!

            if((result.size() > 2) && (result[0] == 'm') && (result[1] == '_'))
            {
                result = result.substr(2);
            }

            //------------------------------------------------------------
            // Split apart camel case

            const std::regex caseExp("([a-z0-9])([A-Z])");
            result = std::regex_replace(result, caseExp, "$1 $2");

            return result;
        }

        //----------------------------------------------------------------------------------
        // PROTECTED METHODS
        //----------------------------------------------------------------------------------

        //----------------------------------------------------------------------------------
        // PRIVATE METHODS
        //----------------------------------------------------------------------------------

        bool Editor::setupEditorCamera()
        {
            bool result = false;

            m_EditorCamera = OcularScene->createObject<Core::Camera>("OCULAR_INTERNAL_EDITOR_CAMERA", nullptr);

            if(m_EditorCamera)
            {
                Core::PerspectiveProjection projection = m_EditorCamera->getPerspectiveProjection();
                projection.farClip = 10000.0f;

                m_EditorCamera->setProjectionPerspective(projection);
                m_EditorCamera->setPersistent(true);
                m_EditorCamera->setPosition(0.0f, 0.2f, 0.5f);
                m_EditorCamera->addRoutine("EditorCameraController");

                result = true;
            }

            return result;
        }

        void Editor::setupAxis()
        {
            const float length = 10000.0f;

            OcularGraphics->drawDebugLine(Math::Vector3f(0.0f, 0.0f, 0.0f), Math::Vector3f(length, 0.0f, 0.0f), Core::Color::Red(), 0);
            OcularGraphics->drawDebugLine(Math::Vector3f(0.0f, 0.0f, 0.0f), Math::Vector3f(0.0f, length, 0.0f), Core::Color::Green(), 0);
            OcularGraphics->drawDebugLine(Math::Vector3f(0.0f, 0.0f, 0.0f), Math::Vector3f(0.0f, 0.0f, length), Core::Color::Blue(), 0);
        }

        void Editor::setupGizmos()
        {
            m_GizmoTranslate = new AxisGizmo();
            m_GizmoTranslate->setName("OCULAR_INTERNAL_EDITOR_GIZMO_TRANSLATE");
            m_GizmoTranslate->setActive(false);
        }

        void Editor::performMousePick(Core::KeyState const state)
        {
            auto mousePos = OcularInput->getMousePosition();
            auto editorCamera = OcularEditor.getEditorCamera();

            if(editorCamera)
            {
                auto ray = editorCamera->getPickRay(mousePos);
                //OcularGraphics->drawDebugLine(ray.getOrigin(), ray.getPointAlong(100.0f), Core::Color::Yellow(), 15000);

                std::vector<std::pair<Core::SceneObject*, float>> intersections;

                OcularScene->getIntersections(ray, intersections);

                if(intersections.size())
                {
                    if(state == Core::KeyState::Released)
                    {
                        // On mouse up, we only care about picking normal (non-gizmo) objects
                        setSelectedObject(intersections[0].first, false, true);
                    }
                    else
                    {
                        // On mouse down, we only care about picking gizmo objects
                        auto gizmo = pickedGizmo(intersections);

                        if(gizmo)
                        {
                            setSelectedObject(gizmo, true, false);
                        }
                    }
                }
                else
                {
                    // If the currently selected object is a gizmo, we simply de-select the gizmo but keep the parent object selected
                    if(m_GizmoTranslate->isSelected())
                    {
                        m_GizmoTranslate->setSelected(false);
                    }
                    else
                    {
                        // No object selected. Treat it as a de-select.
                        setSelectedObject(nullptr, false, true);
                    }
                }
            }
        }

        Core::SceneObject* Editor::pickedGizmo(std::vector<std::pair<Core::SceneObject*, float>> const& intersections) const
        {
            // Check if among the picked items is a gizmo object. If so, we will assume that was the intended pick target.
            Core::SceneObject* result = nullptr;

            for(auto pair : intersections)
            {
                auto object = pair.first;

                if(object)
                {
                    if(OcularString->IsEqual(object->getClass(), OCULAR_TYPE_NAME(AxisComponentGizmo)))
                    {
                        result = object;
                        break;
                    }
                }
            }

            return result;
        }
    }
}<commit_msg>Removing old test code<commit_after>/**
 * Copyright 2014-2017 Steven T Sell (ssell@vertexfragment.com)
 *
 * 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 "stdafx.h"
#include "D3D11GraphicsDriver.hpp"
#include "D3D11DynamicRegistration.hpp"

#include "Events/SceneObjectSelectedEvent.hpp"
#include "Events/SceneObjectFocusedEvent.hpp"
#include "Events/Events/MouseButtonInputEvent.hpp"

#include "Utilities/ColorPicker.hpp"

#include "Widgets/MainStatusBar.hpp"
#include "Widgets/MainWindow.hpp"
#include "Widgets/ContentFrame.hpp"
#include "Widgets/SceneFrame.hpp"
#include "Widgets/SceneTree.hpp"
#include "Widgets/Properties/Renderables/RenderableDisplay.hpp"

#include "Gizmos/Axis/AxisGizmo.hpp"
#include "Gizmos/Axis/AxisComponentGizmo.hpp"
#include "Graphics/Texture/NoiseTexture2D.hpp"
#include "Graphics/Texture/TextureSavers/TextureResourceSaver_PNG.hpp"
#include "Math/Noise/PerlinNoise.hpp"
#include "Math/Noise/SimplexNoise.hpp"
#include "Math/Noise/WaveletNoise.hpp"
#include "OcularEngine.hpp"
#include <regex>

//------------------------------------------------------------------------------------------

namespace Ocular
{
    namespace Editor
    {
        //----------------------------------------------------------------------------------
        // CONSTRUCTORS
        //----------------------------------------------------------------------------------

        Editor& Editor::get()
        {
            static Editor instance;
            return instance;
        }

        Editor::Editor()
            : AEventListener(),
              m_MainWindow(nullptr),
              m_EditorCamera(nullptr),
              m_SelectedObject(nullptr),
              m_FocusedObject(nullptr)
        {

        }

        Editor::~Editor()
        {
            delete m_MainWindow;
            delete m_QtApp;
        }

        //----------------------------------------------------------------------------------
        // PUBLIC METHODS
        //----------------------------------------------------------------------------------

        //----------------------------------------------------------------------------------
        // Core Lifetime Methods
        //----------------------------------------------------------------------------------

        bool Editor::initialize(int argc, char** argv)
        {
            bool result = false;

            m_QtApp = new QApplication(argc, argv);

            if(OcularEngine.initialize(new Ocular::Graphics::D3D11GraphicsDriver()))
            {
                OcularEvents->registerListener(this, Core::Priority::Low);

                m_MainWindow = new MainWindow();
                m_MainWindow->show();
                m_MainWindow->showMaximized();

                if(OcularGraphics->initialize())
                {
                    OcularResources->initialize();   // \todo really bad work around. trying to create default resources before driver is ready otherwise

                    if(setupEditorCamera())
                    {
                        setupAxis();
                        setupGizmos();

                        result = true;
                        OcularLogger->info("Successfully initialized ", OCULAR_VERSION);
                    }
                    else
                    {
                        OcularLogger->error("Failed to initialize Ocular Editor: failed to setup Editor cameras");
                    }
                }
                else
                {
                    OcularLogger->error("Failed to initialize Ocular Editor: failed to initialize Ocular Graphics system");
                }
            }
            else
            {
                OcularLogger->error("Failed to initialize Ocular Editor: failed to initialize Ocular Engine");
            }

            return result;
        }

        void Editor::shutdown()
        {
            OcularEngine.shutdown();
        }

        bool Editor::run()
        {
            bool result = false;

            if(OcularEngine.run())
            {
                m_MainWindow->update();
                m_QtApp->processEvents();

                result = true;
            }

            return result;
        }

        bool Editor::onEvent(std::shared_ptr<Core::AEvent> event)
        {
            if(event->isType<SceneObjectSelectedEvent>())
            {
                SceneObjectSelectedEvent* cast = dynamic_cast<SceneObjectSelectedEvent*>(event.get());
                m_SelectedObject = cast->object;
            }
            else if(event->isType<SceneObjectFocusedEvent>())
            {
                SceneObjectFocusedEvent* cast = dynamic_cast<SceneObjectFocusedEvent*>(event.get());
                m_FocusedObject = cast->object;
            }
            else if(event->isType<Core::MouseButtonInputEvent>())
            {
                Core::MouseButtonInputEvent* cast = dynamic_cast<Core::MouseButtonInputEvent*>(event.get());

                if(cast->button == Core::MouseButtons::Left)
                {
                    // Check if alt key is down (we assume a rotation around target if it is down)
                    if(!OcularInput->isKeyboardKeyDown(Core::KeyboardKeys::AltLeft))
                    {
                        performMousePick(cast->state);
                    }
                }
            }

            return true;
        }

        //----------------------------------------------------------------------------------
        // Primary Getters
        //----------------------------------------------------------------------------------

        MainWindow* Editor::getMainWindow() const
        {
            return m_MainWindow;
        }

        Core::Camera* Editor::getEditorCamera() const
        {
            return m_EditorCamera;
        }

        void Editor::setSelectedObject(Core::SceneObject* object, bool ignoreNormalObject, bool ignoreGizmoObject)
        {
            std::shared_ptr<Core::AEvent> event = nullptr;

            m_GizmoTranslate->setSelected(false);

            if(object)
            {
                m_GizmoTranslate->setActive(true);

                Gizmo* gizmo = dynamic_cast<Gizmo*>(object);

                if(gizmo)
                {
                    // If the selected object was a gizmo (or part of a gizmo), we can not
                    // set it as the selected object for obvious reasons.

                    // Instead we notify the gizmo that it has been selected (so that it can
                    // handle dragging, etc.) and maintain the current selected object.

                    if(!ignoreGizmoObject)
                    {
                        gizmo->setSelected(true);
                    }
                }
                else
                {
                    if(!ignoreNormalObject)
                    {
                        m_SelectedObject = object;

                        m_MainWindow->getContentFrame()->getSceneFrame()->getSceneTree()->selectObject(m_SelectedObject);
                        m_SelectedObject->addChild(m_GizmoTranslate, false);

                        event = std::make_shared<SceneObjectSelectedEvent>(m_SelectedObject);
                    }
                }
            }
            else
            {
                // Deselect

                m_GizmoTranslate->setActive(false);
                m_GizmoTranslate->setParent(nullptr, false);

                m_MainWindow->getContentFrame()->getSceneFrame()->getSceneTree()->selectObject(nullptr);

                event = std::make_shared<SceneObjectSelectedEvent>(nullptr);
            }

            if(event)
            {
                OcularEvents->queueEvent(event);
            }
        }

        Core::SceneObject* Editor::getSelectedObject() const
        {
            return m_SelectedObject;
        }

        Core::SceneObject* Editor::getFocusedObject() const
        {
            return m_FocusedObject;
        }

        //----------------------------------------------------------------------------------
        // Misc Methods
        //----------------------------------------------------------------------------------

        void Editor::setStatusNormal(std::string const& message)
        {
            auto statusBar = m_MainWindow->getMainStatusBar();

            if(statusBar)
            {
                statusBar->addWidget(new QLabel(message.c_str()));
            }
        }

        void Editor::setStatusPermanent(std::string const& message)
        {
            auto statusBar = m_MainWindow->getMainStatusBar();

            if(statusBar)
            {
                statusBar->setPermanentMessage(message.c_str());
            }
        }

        void Editor::setStatusTemporary(std::string const& message, uint32_t const lifetime)
        {
            auto statusBar = m_MainWindow->getMainStatusBar();

            if(statusBar)
            {
                statusBar->showMessage(message.c_str(), lifetime);
            }
        }

        void Editor::setStatusNormalProgress(std::string const& message, uint32_t const progress)
        {
            throw std::exception("implement me");
        }

        //----------------------------------------------------------------------------------
        // Widget Factories
        //----------------------------------------------------------------------------------

        PropertyWidget* Editor::createPropertyWidget(std::string const& displayName, std::string const& type)
        {
            PropertyWidget* result = m_PropertyWidgetFactory.createComponent(type);

            if(result)
            {
                result->setDisplayName(displayName);
            }

            return result;
        }

        Core::ComponentFactory<PropertyWidget>& Editor::getPropertyWidgetFactory()
        {
            return m_PropertyWidgetFactory;
        }

        PropertiesDisplayBox* Editor::createCustomDisplay(std::string const& type)
        {
            PropertiesDisplayBox* result = m_CustomDisplayFactory.createComponent(type);

            if(result)
            {
                result->setTitle(type.c_str());
            }

            return result;
        }

        Core::ComponentFactory<PropertiesDisplayBox>& Editor::getCustomDisplayFactory()
        {
            return m_CustomDisplayFactory;
        }

        RenderableDisplay* Editor::createRenderableDisplay(std::string const& type)
        {
            RenderableDisplay* result = m_RenderableDisplayFactory.createComponent(type);

            if(result)
            {
                result->setTitle(type.c_str());
            }

            return result;
        }

        Core::ComponentFactory<RenderableDisplay>& Editor::getRenderableDisplayFactory()
        {
            return m_RenderableDisplayFactory;
        }

        //----------------------------------------------------------------------------------
        // Static Methods
        //----------------------------------------------------------------------------------

        bool Editor::IsCommonName(std::string const& name)
        {
            bool result = false;

            static std::string CommonNames[8] =
            {
                "m_IsActive",
                "m_Name",
                "m_Position",
                "m_Rotation",
                "m_Scale",
                "m_Class",
                "m_IsStatic",
                "m_ForcedVisible"
            };

            for(auto commonName : CommonNames)
            {
                if(Utils::String::IsEqual(name, commonName))
                {
                    result = true;
                    break;
                }
            }

            return result;
        }

        std::string Editor::FormatName(std::string const& name)
        {
            std::string result = name;

            //------------------------------------------------------------
            // Remove any "m_"

            // Do regex instead!

            if((result.size() > 2) && (result[0] == 'm') && (result[1] == '_'))
            {
                result = result.substr(2);
            }

            //------------------------------------------------------------
            // Split apart camel case

            const std::regex caseExp("([a-z0-9])([A-Z])");
            result = std::regex_replace(result, caseExp, "$1 $2");

            return result;
        }

        //----------------------------------------------------------------------------------
        // PROTECTED METHODS
        //----------------------------------------------------------------------------------

        //----------------------------------------------------------------------------------
        // PRIVATE METHODS
        //----------------------------------------------------------------------------------

        bool Editor::setupEditorCamera()
        {
            bool result = false;

            m_EditorCamera = OcularScene->createObject<Core::Camera>("OCULAR_INTERNAL_EDITOR_CAMERA", nullptr);

            if(m_EditorCamera)
            {
                Core::PerspectiveProjection projection = m_EditorCamera->getPerspectiveProjection();
                projection.farClip = 10000.0f;

                m_EditorCamera->setProjectionPerspective(projection);
                m_EditorCamera->setPersistent(true);
                m_EditorCamera->setPosition(0.0f, 0.2f, 0.5f);
                m_EditorCamera->addRoutine("EditorCameraController");

                result = true;
            }

            return result;
        }

        void Editor::setupAxis()
        {
            const float length = 10000.0f;

            OcularGraphics->drawDebugLine(Math::Vector3f(0.0f, 0.0f, 0.0f), Math::Vector3f(length, 0.0f, 0.0f), Core::Color::Red(), 0);
            OcularGraphics->drawDebugLine(Math::Vector3f(0.0f, 0.0f, 0.0f), Math::Vector3f(0.0f, length, 0.0f), Core::Color::Green(), 0);
            OcularGraphics->drawDebugLine(Math::Vector3f(0.0f, 0.0f, 0.0f), Math::Vector3f(0.0f, 0.0f, length), Core::Color::Blue(), 0);
        }

        void Editor::setupGizmos()
        {
            m_GizmoTranslate = new AxisGizmo();
            m_GizmoTranslate->setName("OCULAR_INTERNAL_EDITOR_GIZMO_TRANSLATE");
            m_GizmoTranslate->setActive(false);
        }

        void Editor::performMousePick(Core::KeyState const state)
        {
            auto mousePos = OcularInput->getMousePosition();
            auto editorCamera = OcularEditor.getEditorCamera();

            if(editorCamera)
            {
                auto ray = editorCamera->getPickRay(mousePos);
                //OcularGraphics->drawDebugLine(ray.getOrigin(), ray.getPointAlong(100.0f), Core::Color::Yellow(), 15000);

                std::vector<std::pair<Core::SceneObject*, float>> intersections;

                OcularScene->getIntersections(ray, intersections);

                if(intersections.size())
                {
                    if(state == Core::KeyState::Released)
                    {
                        // On mouse up, we only care about picking normal (non-gizmo) objects
                        setSelectedObject(intersections[0].first, false, true);
                    }
                    else
                    {
                        // On mouse down, we only care about picking gizmo objects
                        auto gizmo = pickedGizmo(intersections);

                        if(gizmo)
                        {
                            setSelectedObject(gizmo, true, false);
                        }
                    }
                }
                else
                {
                    // If the currently selected object is a gizmo, we simply de-select the gizmo but keep the parent object selected
                    if(m_GizmoTranslate->isSelected())
                    {
                        m_GizmoTranslate->setSelected(false);
                    }
                    else
                    {
                        // No object selected. Treat it as a de-select.
                        setSelectedObject(nullptr, false, true);
                    }
                }
            }
        }

        Core::SceneObject* Editor::pickedGizmo(std::vector<std::pair<Core::SceneObject*, float>> const& intersections) const
        {
            // Check if among the picked items is a gizmo object. If so, we will assume that was the intended pick target.
            Core::SceneObject* result = nullptr;

            for(auto pair : intersections)
            {
                auto object = pair.first;

                if(object)
                {
                    if(OcularString->IsEqual(object->getClass(), OCULAR_TYPE_NAME(AxisComponentGizmo)))
                    {
                        result = object;
                        break;
                    }
                }
            }

            return result;
        }
    }
}<|endoftext|>


<commit_before>#include "TRCFileAdapter.h"
#include <fstream>

namespace OpenSim {

const std::string TRCFileAdapter::_markers{"markers"};
const std::string TRCFileAdapter::_delimiterWrite{"\t"};
const std::string TRCFileAdapter::_delimitersRead{" \t"};
const std::string TRCFileAdapter::_frameNumColumnLabel{"Frame#"};
const std::string TRCFileAdapter::_timeColumnLabel{"Time"};
const std::string TRCFileAdapter::_xLabel{"X"};
const std::string TRCFileAdapter::_yLabel{"Y"};
const std::string TRCFileAdapter::_zLabel{"Z"};
const std::string TRCFileAdapter::_numMarkersLabel{"NumMarkers"};
const std::string TRCFileAdapter::_numFramesLabel{"NumFrames"};
const unsigned    TRCFileAdapter::_dataStartsAtLine{6};
const std::vector<std::string> TRCFileAdapter::_metadataKeys{"DataRate",
        "CameraRate", "NumFrames", "NumMarkers", "Units", "OrigDataRate",
        "OrigDataStartFrame", "OrigNumFrames"};

TRCFileAdapter*
TRCFileAdapter::clone() const {
    return new TRCFileAdapter{*this};
}

TimeSeriesTableVec3
TRCFileAdapter::read(const std::string& fileName) const {
    auto abs_table = extendRead(fileName).at(_markers);
    return static_cast<TimeSeriesTableVec3&>(*abs_table);
}

void
TRCFileAdapter::write(const TimeSeriesTableVec3& table,
                      const std::string& fileName) const {
    InputTables tables{};
    tables.emplace(_markers, &table);
    extendWrite(tables, fileName);
}

TRCFileAdapter::OutputTables
TRCFileAdapter::extendRead(const std::string& fileName) const {
    OPENSIM_THROW_IF(fileName.empty(),
                     EmptyFileName);

    std::ifstream in_stream{fileName};
    OPENSIM_THROW_IF(!in_stream.good(),
                     FileDoesNotExist,
                     fileName);

    auto table = std::make_shared<TimeSeriesTableVec3>();

    // Callable to get the next line in form of vector of tokens.
    auto nextLine = [&] {
        return getNextLine(in_stream, _delimitersRead);
    };

    // First line of the stream is considered the header.
    std::string header{};
    std::getline(in_stream, header);
    auto header_tokens = tokenize(header, _delimitersRead);
    OPENSIM_THROW_IF(header_tokens.empty(),
                     FileIsEmpty,
                     fileName);
    OPENSIM_THROW_IF(header_tokens.at(0) != "PathFileType",
                     MissingHeader);
    table->updTableMetaData().setValueForKey("header", header);

    // Read the line containing metadata keys.
    auto keys = nextLine();
    OPENSIM_THROW_IF(keys.size() != _metadataKeys.size(),
                     IncorrectNumMetaDataKeys,
                     fileName,
                     _metadataKeys.size(),
                     keys.size());

    for(size_t i = 0; i < keys.size(); ++i)
        OPENSIM_THROW_IF(keys[i] != _metadataKeys[i],
                         UnexpectedMetaDataKey,
                         fileName,
                         _metadataKeys[i],
                         keys[i]);

    // Read the line containing metadata values.
    auto values = nextLine();
    OPENSIM_THROW_IF(keys.size() != values.size(),
                     MetaDataLengthMismatch,
                     fileName,
                     keys.size(),
                     values.size());

    // Fill up the metadata container.
    for(std::size_t i = 0; i < keys.size(); ++i)
        table->updTableMetaData().setValueForKey(keys[i], values[i]);

    auto num_markers_expected =
        std::stoul(table->
                   getTableMetaData().
                   getValueForKey(_numMarkersLabel).
                   template getValue<std::string>());

    // Read the line containing column labels and fill up the column labels
    // container.
    auto column_labels = nextLine();
    OPENSIM_THROW_IF(column_labels.size() != num_markers_expected + 2,
                     IncorrectNumColumnLabels,
                     fileName,
                     num_markers_expected + 2,
                     column_labels.size());

    // Column 0 should be the frame number. Check and get rid of it as it is
    // not used. The whole column is discarded as the data is read in.
    OPENSIM_THROW_IF(column_labels[0] != _frameNumColumnLabel,
                     UnexpectedColumnLabel,
                     fileName,
                     _frameNumColumnLabel,
                     column_labels[0]);
    column_labels.erase(column_labels.begin());

    // Column 0 (originally column 1 before removing frame number) should
    // now be the time column. Check and get rid of it. The data in this
    // column is maintained separately from rest of the data.
    OPENSIM_THROW_IF(column_labels[0] != _timeColumnLabel,
                     UnexpectedColumnLabel,
                     fileName,
                     _timeColumnLabel,
                     column_labels[0]);
    column_labels.erase(column_labels.begin());

    // Read in the next line of column labels containing (Xdd, Ydd, Zdd)
    // tuples where dd is a 1 or 2 digit subscript. For example --
    // X1, Y1, Z1, X2, Y2, Z2, ... so on.
    // Check and ignore these labels.
    auto xyz_labels_found = nextLine();
    for(int i = 1; i <= num_markers_expected; ++i) {
        size_t j = 0;
        for(auto& letter : {_xLabel, _yLabel, _zLabel}) {
            const size_t ind = ((i - 1) * 3) + j++;
            const std::string expected{letter + std::to_string(i)};
            OPENSIM_THROW_IF(xyz_labels_found.at(ind) != expected,
                             UnexpectedColumnLabel,
                             fileName,
                             expected,
                             xyz_labels_found.at(ind));
        }
    }

    // Read the rows one at a time and fill up the time column container and
    // the data container.
    std::size_t line_num{_dataStartsAtLine - 1};
    auto row = nextLine();
    while(!row.empty()) {
        ++line_num;
        size_t expected{column_labels.size() * 3 + 2};
        OPENSIM_THROW_IF(row.size() != expected,
                         RowLengthMismatch,
                         fileName,
                         line_num,
                         expected,
                         row.size());

        // Columns 2 till the end are data.
        TimeSeriesTableVec3::RowVector
            row_vector{static_cast<int>(num_markers_expected)};
        size_t ind{0};
        for(std::size_t c = 2; c < column_labels.size() * 3 + 2; c += 3)
            row_vector[ind++] = SimTK::Vec3{std::stod(row.at(c)),
                                            std::stod(row.at(c+1)),
                                            std::stod(row.at(c+2))};

        // Column 1 is time.
        table->appendRow(std::stod(row.at(1)), std::move(row_vector));

        row = nextLine();
    }

    // Set the column labels of the table.
    ValueArray<std::string> value_array{};
    for(const auto& cl : column_labels)
        value_array.upd().push_back(SimTK::Value<std::string>{cl});
    TimeSeriesTableVec3::DependentsMetaData dep_metadata{};
    dep_metadata.setValueArrayForKey("labels", value_array);
    table->setDependentsMetaData(dep_metadata);

    OutputTables output_tables{};
    output_tables.emplace(_markers, table);

    return output_tables;
}

void
TRCFileAdapter::extendWrite(const InputTables& absTables,
                            const std::string& fileName) const {
    OPENSIM_THROW_IF(absTables.empty(),
                     NoTableFound);

    const TimeSeriesTableVec3* table{};
    try {
        auto abs_table = absTables.at(_markers);
        table = dynamic_cast<const TimeSeriesTableVec3*>(abs_table);
    } catch(std::out_of_range) {
        OPENSIM_THROW(KeyMissing,
                      _markers);
    } catch(std::bad_cast&) {
        OPENSIM_THROW(IncorrectTableType);
    }

    OPENSIM_THROW_IF(fileName.empty(),
                     EmptyFileName);

    std::ofstream out_stream{fileName};

    // First line of the stream is the header.
    try {
    out_stream << table->
                  getTableMetaData().
                  getValueForKey("header").
                  getValue<std::string>() << "\n";
    } catch(KeyNotFound&) {
        out_stream << "PathFileType\t4\t(X/Y/Z)\t" << fileName << "\n";
    }

    // Line containing metadata keys.
    out_stream << _metadataKeys[0];
    for(unsigned i = 1; i < _metadataKeys.size(); ++i)
        out_stream << _delimiterWrite << _metadataKeys[i];
    out_stream << "\n";

    // Line containing metadata values.
    std::string datarate;
    try {
        datarate = table->
                   getTableMetaData().
                   getValueForKey(_metadataKeys[0]).
                   getValue<std::string>();
    } catch(KeyNotFound&) {
        OPENSIM_THROW(MissingMetaData,
                      "DataRate");
    }
    out_stream << datarate << _delimiterWrite;
    try {
        out_stream << table->
                      getTableMetaData().
                      getValueForKey(_metadataKeys[1]).
                      getValue<std::string>()
                   << _delimiterWrite;
    } catch(KeyNotFound&) {
        out_stream << datarate << _delimiterWrite;
    }
    try {
        out_stream << table->
                      getTableMetaData().
                      getValueForKey(_metadataKeys[2]).
                      getValue<std::string>()
                   << _delimiterWrite;
    } catch(KeyNotFound&) {
        out_stream << table->getNumRows() << _delimiterWrite;
    }
    try {
        out_stream << table->
                      getTableMetaData().
                      getValueForKey(_metadataKeys[3]).
                      getValue<std::string>()
                   << _delimiterWrite;
    } catch(KeyNotFound&) {
        out_stream << table->getNumColumns() << _delimiterWrite;
    }
    try {
        out_stream << table->
                      getTableMetaData().
                      getValueForKey(_metadataKeys[4]).
                      getValue<std::string>()
                   << _delimiterWrite;
    } catch(KeyNotFound&) {
        OPENSIM_THROW(MissingMetaData,
                      "Units");
    }
    try {
        out_stream << table->
                      getTableMetaData().
                      getValueForKey(_metadataKeys[5]).
                      getValue<std::string>()
                   << _delimiterWrite;
    } catch(KeyNotFound&) {
        out_stream << datarate << _delimiterWrite;
    }
    try {
        out_stream << table->
                      getTableMetaData().
                      getValueForKey(_metadataKeys[6]).
                      getValue<std::string>()
                   << _delimiterWrite;
    } catch(KeyNotFound&) {
        out_stream << 0 << _delimiterWrite;
    }
    try {
        out_stream << table->
                      getTableMetaData().
                      getValueForKey(_metadataKeys[7]).
                      getValue<std::string>();
    } catch(KeyNotFound&) {
        out_stream << table->getNumRows();
    }
    out_stream << "\n";

    // Line containing column labels.
    out_stream << _frameNumColumnLabel << _delimiterWrite
               << _timeColumnLabel     << _delimiterWrite;
    for(unsigned col = 0; col < table->getNumColumns(); ++col)
        out_stream << table->
                      getDependentsMetaData().
                      getValueArrayForKey("labels")[col].
                      getValue<std::string>()
                   << _delimiterWrite << _delimiterWrite << _delimiterWrite;
    out_stream << "\n";

    // Line containing xyz component labels for each marker.
    out_stream << _delimiterWrite << _delimiterWrite;
    for(unsigned col = 1; col <= table->getNumColumns(); ++col)
        for(auto& letter : {_xLabel, _yLabel, _zLabel})
            out_stream << (letter + std::to_string(col)) << _delimiterWrite;
    out_stream << "\n";

    // Empty line.
    out_stream << "\n";

    // Data rows.
    for(unsigned row = 0; row < table->getNumRows(); ++row) {
        constexpr auto prec = std::numeric_limits<double>::digits10 + 1;
        out_stream << row + 1                           << _delimiterWrite
                   << std::setprecision(prec)
                   << table->getIndependentColumn()[row] << _delimiterWrite;
        const auto& row_r = table->getRowAtIndex(row);
        for(unsigned col = 0; col < table->getNumColumns(); ++col) {
            const auto& elt = row_r[col];
            out_stream << std::setprecision(prec)
                       << elt[0] << _delimiterWrite
                       << elt[1] << _delimiterWrite
                       << elt[2] << _delimiterWrite;
        }
        out_stream << "\n";
    }
}

}
<commit_msg>Change to int to avoid warning.<commit_after>#include "TRCFileAdapter.h"
#include <fstream>

namespace OpenSim {

const std::string TRCFileAdapter::_markers{"markers"};
const std::string TRCFileAdapter::_delimiterWrite{"\t"};
const std::string TRCFileAdapter::_delimitersRead{" \t"};
const std::string TRCFileAdapter::_frameNumColumnLabel{"Frame#"};
const std::string TRCFileAdapter::_timeColumnLabel{"Time"};
const std::string TRCFileAdapter::_xLabel{"X"};
const std::string TRCFileAdapter::_yLabel{"Y"};
const std::string TRCFileAdapter::_zLabel{"Z"};
const std::string TRCFileAdapter::_numMarkersLabel{"NumMarkers"};
const std::string TRCFileAdapter::_numFramesLabel{"NumFrames"};
const unsigned    TRCFileAdapter::_dataStartsAtLine{6};
const std::vector<std::string> TRCFileAdapter::_metadataKeys{"DataRate",
        "CameraRate", "NumFrames", "NumMarkers", "Units", "OrigDataRate",
        "OrigDataStartFrame", "OrigNumFrames"};

TRCFileAdapter*
TRCFileAdapter::clone() const {
    return new TRCFileAdapter{*this};
}

TimeSeriesTableVec3
TRCFileAdapter::read(const std::string& fileName) const {
    auto abs_table = extendRead(fileName).at(_markers);
    return static_cast<TimeSeriesTableVec3&>(*abs_table);
}

void
TRCFileAdapter::write(const TimeSeriesTableVec3& table,
                      const std::string& fileName) const {
    InputTables tables{};
    tables.emplace(_markers, &table);
    extendWrite(tables, fileName);
}

TRCFileAdapter::OutputTables
TRCFileAdapter::extendRead(const std::string& fileName) const {
    OPENSIM_THROW_IF(fileName.empty(),
                     EmptyFileName);

    std::ifstream in_stream{fileName};
    OPENSIM_THROW_IF(!in_stream.good(),
                     FileDoesNotExist,
                     fileName);

    auto table = std::make_shared<TimeSeriesTableVec3>();

    // Callable to get the next line in form of vector of tokens.
    auto nextLine = [&] {
        return getNextLine(in_stream, _delimitersRead);
    };

    // First line of the stream is considered the header.
    std::string header{};
    std::getline(in_stream, header);
    auto header_tokens = tokenize(header, _delimitersRead);
    OPENSIM_THROW_IF(header_tokens.empty(),
                     FileIsEmpty,
                     fileName);
    OPENSIM_THROW_IF(header_tokens.at(0) != "PathFileType",
                     MissingHeader);
    table->updTableMetaData().setValueForKey("header", header);

    // Read the line containing metadata keys.
    auto keys = nextLine();
    OPENSIM_THROW_IF(keys.size() != _metadataKeys.size(),
                     IncorrectNumMetaDataKeys,
                     fileName,
                     _metadataKeys.size(),
                     keys.size());

    for(size_t i = 0; i < keys.size(); ++i)
        OPENSIM_THROW_IF(keys[i] != _metadataKeys[i],
                         UnexpectedMetaDataKey,
                         fileName,
                         _metadataKeys[i],
                         keys[i]);

    // Read the line containing metadata values.
    auto values = nextLine();
    OPENSIM_THROW_IF(keys.size() != values.size(),
                     MetaDataLengthMismatch,
                     fileName,
                     keys.size(),
                     values.size());

    // Fill up the metadata container.
    for(std::size_t i = 0; i < keys.size(); ++i)
        table->updTableMetaData().setValueForKey(keys[i], values[i]);

    auto num_markers_expected =
        std::stoul(table->
                   getTableMetaData().
                   getValueForKey(_numMarkersLabel).
                   template getValue<std::string>());

    // Read the line containing column labels and fill up the column labels
    // container.
    auto column_labels = nextLine();
    OPENSIM_THROW_IF(column_labels.size() != num_markers_expected + 2,
                     IncorrectNumColumnLabels,
                     fileName,
                     num_markers_expected + 2,
                     column_labels.size());

    // Column 0 should be the frame number. Check and get rid of it as it is
    // not used. The whole column is discarded as the data is read in.
    OPENSIM_THROW_IF(column_labels[0] != _frameNumColumnLabel,
                     UnexpectedColumnLabel,
                     fileName,
                     _frameNumColumnLabel,
                     column_labels[0]);
    column_labels.erase(column_labels.begin());

    // Column 0 (originally column 1 before removing frame number) should
    // now be the time column. Check and get rid of it. The data in this
    // column is maintained separately from rest of the data.
    OPENSIM_THROW_IF(column_labels[0] != _timeColumnLabel,
                     UnexpectedColumnLabel,
                     fileName,
                     _timeColumnLabel,
                     column_labels[0]);
    column_labels.erase(column_labels.begin());

    // Read in the next line of column labels containing (Xdd, Ydd, Zdd)
    // tuples where dd is a 1 or 2 digit subscript. For example --
    // X1, Y1, Z1, X2, Y2, Z2, ... so on.
    // Check and ignore these labels.
    auto xyz_labels_found = nextLine();
    for(int i = 1; i <= num_markers_expected; ++i) {
        size_t j = 0;
        for(auto& letter : {_xLabel, _yLabel, _zLabel}) {
            const size_t ind = ((i - 1) * 3) + j++;
            const std::string expected{letter + std::to_string(i)};
            OPENSIM_THROW_IF(xyz_labels_found.at(ind) != expected,
                             UnexpectedColumnLabel,
                             fileName,
                             expected,
                             xyz_labels_found.at(ind));
        }
    }

    // Read the rows one at a time and fill up the time column container and
    // the data container.
    std::size_t line_num{_dataStartsAtLine - 1};
    auto row = nextLine();
    while(!row.empty()) {
        ++line_num;
        size_t expected{column_labels.size() * 3 + 2};
        OPENSIM_THROW_IF(row.size() != expected,
                         RowLengthMismatch,
                         fileName,
                         line_num,
                         expected,
                         row.size());

        // Columns 2 till the end are data.
        TimeSeriesTableVec3::RowVector
            row_vector{static_cast<int>(num_markers_expected)};
        int ind{0};
        for(std::size_t c = 2; c < column_labels.size() * 3 + 2; c += 3)
            row_vector[ind++] = SimTK::Vec3{std::stod(row.at(c)),
                                            std::stod(row.at(c+1)),
                                            std::stod(row.at(c+2))};

        // Column 1 is time.
        table->appendRow(std::stod(row.at(1)), std::move(row_vector));

        row = nextLine();
    }

    // Set the column labels of the table.
    ValueArray<std::string> value_array{};
    for(const auto& cl : column_labels)
        value_array.upd().push_back(SimTK::Value<std::string>{cl});
    TimeSeriesTableVec3::DependentsMetaData dep_metadata{};
    dep_metadata.setValueArrayForKey("labels", value_array);
    table->setDependentsMetaData(dep_metadata);

    OutputTables output_tables{};
    output_tables.emplace(_markers, table);

    return output_tables;
}

void
TRCFileAdapter::extendWrite(const InputTables& absTables,
                            const std::string& fileName) const {
    OPENSIM_THROW_IF(absTables.empty(),
                     NoTableFound);

    const TimeSeriesTableVec3* table{};
    try {
        auto abs_table = absTables.at(_markers);
        table = dynamic_cast<const TimeSeriesTableVec3*>(abs_table);
    } catch(std::out_of_range) {
        OPENSIM_THROW(KeyMissing,
                      _markers);
    } catch(std::bad_cast&) {
        OPENSIM_THROW(IncorrectTableType);
    }

    OPENSIM_THROW_IF(fileName.empty(),
                     EmptyFileName);

    std::ofstream out_stream{fileName};

    // First line of the stream is the header.
    try {
    out_stream << table->
                  getTableMetaData().
                  getValueForKey("header").
                  getValue<std::string>() << "\n";
    } catch(KeyNotFound&) {
        out_stream << "PathFileType\t4\t(X/Y/Z)\t" << fileName << "\n";
    }

    // Line containing metadata keys.
    out_stream << _metadataKeys[0];
    for(unsigned i = 1; i < _metadataKeys.size(); ++i)
        out_stream << _delimiterWrite << _metadataKeys[i];
    out_stream << "\n";

    // Line containing metadata values.
    std::string datarate;
    try {
        datarate = table->
                   getTableMetaData().
                   getValueForKey(_metadataKeys[0]).
                   getValue<std::string>();
    } catch(KeyNotFound&) {
        OPENSIM_THROW(MissingMetaData,
                      "DataRate");
    }
    out_stream << datarate << _delimiterWrite;
    try {
        out_stream << table->
                      getTableMetaData().
                      getValueForKey(_metadataKeys[1]).
                      getValue<std::string>()
                   << _delimiterWrite;
    } catch(KeyNotFound&) {
        out_stream << datarate << _delimiterWrite;
    }
    try {
        out_stream << table->
                      getTableMetaData().
                      getValueForKey(_metadataKeys[2]).
                      getValue<std::string>()
                   << _delimiterWrite;
    } catch(KeyNotFound&) {
        out_stream << table->getNumRows() << _delimiterWrite;
    }
    try {
        out_stream << table->
                      getTableMetaData().
                      getValueForKey(_metadataKeys[3]).
                      getValue<std::string>()
                   << _delimiterWrite;
    } catch(KeyNotFound&) {
        out_stream << table->getNumColumns() << _delimiterWrite;
    }
    try {
        out_stream << table->
                      getTableMetaData().
                      getValueForKey(_metadataKeys[4]).
                      getValue<std::string>()
                   << _delimiterWrite;
    } catch(KeyNotFound&) {
        OPENSIM_THROW(MissingMetaData,
                      "Units");
    }
    try {
        out_stream << table->
                      getTableMetaData().
                      getValueForKey(_metadataKeys[5]).
                      getValue<std::string>()
                   << _delimiterWrite;
    } catch(KeyNotFound&) {
        out_stream << datarate << _delimiterWrite;
    }
    try {
        out_stream << table->
                      getTableMetaData().
                      getValueForKey(_metadataKeys[6]).
                      getValue<std::string>()
                   << _delimiterWrite;
    } catch(KeyNotFound&) {
        out_stream << 0 << _delimiterWrite;
    }
    try {
        out_stream << table->
                      getTableMetaData().
                      getValueForKey(_metadataKeys[7]).
                      getValue<std::string>();
    } catch(KeyNotFound&) {
        out_stream << table->getNumRows();
    }
    out_stream << "\n";

    // Line containing column labels.
    out_stream << _frameNumColumnLabel << _delimiterWrite
               << _timeColumnLabel     << _delimiterWrite;
    for(unsigned col = 0; col < table->getNumColumns(); ++col)
        out_stream << table->
                      getDependentsMetaData().
                      getValueArrayForKey("labels")[col].
                      getValue<std::string>()
                   << _delimiterWrite << _delimiterWrite << _delimiterWrite;
    out_stream << "\n";

    // Line containing xyz component labels for each marker.
    out_stream << _delimiterWrite << _delimiterWrite;
    for(unsigned col = 1; col <= table->getNumColumns(); ++col)
        for(auto& letter : {_xLabel, _yLabel, _zLabel})
            out_stream << (letter + std::to_string(col)) << _delimiterWrite;
    out_stream << "\n";

    // Empty line.
    out_stream << "\n";

    // Data rows.
    for(unsigned row = 0; row < table->getNumRows(); ++row) {
        constexpr auto prec = std::numeric_limits<double>::digits10 + 1;
        out_stream << row + 1                           << _delimiterWrite
                   << std::setprecision(prec)
                   << table->getIndependentColumn()[row] << _delimiterWrite;
        const auto& row_r = table->getRowAtIndex(row);
        for(unsigned col = 0; col < table->getNumColumns(); ++col) {
            const auto& elt = row_r[col];
            out_stream << std::setprecision(prec)
                       << elt[0] << _delimiterWrite
                       << elt[1] << _delimiterWrite
                       << elt[2] << _delimiterWrite;
        }
        out_stream << "\n";
    }
}

}
<|endoftext|>


<commit_before>/*
 * Copyright (c) 2014 David Wicks, sansumbrella.com
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or
 * without modification, are permitted provided that the following
 * conditions are met:
 *
 * Redistributions of source code must retain the above copyright
 * notice, this list of conditions and the following disclaimer.
 * Redistributions in binary form must reproduce the above copyright
 * notice, this list of conditions and the following disclaimer in the
 * documentation and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
 * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

#include "Loops.h"

using namespace choreograph;
using namespace cinder;

void Loops::setup()
{
  float left = 100.0f;
  float right = app::getWindowWidth() - left;
  PhraseRef<vec2> leftToRight = makeRamp( vec2( left, 0.0f ), vec2( right, 0.0f ), 1.0f, EaseInOutQuad() );

  //=====================================================
  // Looping Motions. Use for things that loop "forever."
  //=====================================================

  Output<vec2>  loopTarget;
  timeline().apply( &loopTarget, leftToRight )
    .finishFn( [] ( Motion<vec2> &m ) {
      m.resetTime();
    } );  // Motion should play forever.

  Output<vec2>  pingPongTarget;
  timeline().apply( &pingPongTarget, leftToRight )
    .finishFn( [] ( Motion<vec2> &m ) {
      // reverse Motion direction on finish.
      m.setPlaybackSpeed( m.getPlaybackSpeed() * -1 );
      // Start each cycle from "zero" to keep in sync with loopTarget timing.
      m.resetTime();
    } );

  Output<vec2>  pingPongSlowerTarget;
  timeline().apply( &pingPongSlowerTarget, leftToRight )
    .finishFn( [] ( Motion<vec2> &m ) {
      // Reverse and slow Motion on finish.
      m.setPlaybackSpeed( m.getPlaybackSpeed() * -0.9f );
      // If we're unbearably slow, stop looping.
      if( std::abs( m.getPlaybackSpeed() ) < 0.2f ) {
        m.finishFn( [] ( Motion<vec2> &m ) {} );
      }
      else {
        m.resetTime();
      }
    } );

  //==========================================================
  // Looping Motion Group. Use for separate motions that loop
  // with each other, but have different durations.
  //==========================================================

  SequenceRef<vec2> positionSequence = createSequence( vec2( app::getWindowSize() ) * vec2( 0.66, 1 ) + vec2( 0, 50 ) );
  SequenceRef<vec3> rotationSequence = createSequence( vec3( M_PI / 2, 0, 0 ) );

  rotationSequence->then<RampTo>( vec3( 4 * M_PI, 2 * M_PI, 0 ), 1.0f, EaseOutQuint() );
  positionSequence->then<RampTo>( vec2( app::getWindowSize() ) * vec2( 0.66, 0.5 ), 0.5f, EaseOutAtan() );

  auto group = std::make_shared<MotionGroup>();
  group->add( positionSequence, &_position );
  group->add( rotationSequence, &_rotation );
  group->setStartTime( 0.5f ); // start all motions after a 0.5 second hold on their start values.
  group->setFinishFn( [] ( MotionGroup &group ) {
    group.setPlaybackSpeed( group.getPlaybackSpeed() * -1 );
    group.resetTime();
  } );

  timeline().add( group );

  //=====================================================
  // Looping Phrases. Use for a finite number of loops.
  //=====================================================

  Output<vec2> loopPhraseTarget;
  timeline().apply( &loopPhraseTarget ).then( makeRepeat( leftToRight, 7.5f ) );

  Output<vec2> pingPongPhraseTarget;
  timeline().apply( &pingPongPhraseTarget ).then( makePingPong( leftToRight, 7.5f ) );

  mTargets.push_back( { loopTarget, Color( 1, 0, 1 ) } );
  mTargets.push_back( { pingPongTarget, Color( 1, 0, 1 ) } );
  mTargets.push_back( { pingPongSlowerTarget, Color( 0, 1, 1 ) } );
  mTargets.push_back( { loopPhraseTarget, Color( 1, 1, 0 ) } );
  mTargets.push_back( { pingPongPhraseTarget, Color( 1, 1, 0 ) } );
}

void Loops::update( double dt )
{
  timeline().step( dt );
}

void Loops::draw()
{
  gl::ScopedModelMatrix matrix;
  gl::setMatricesWindowPersp( app::getWindowSize() );

  {
    gl::ScopedModelMatrix singleDotMatrix;

    const float y_step = 100.0f;
    gl::translate( vec2( 0, (app::getWindowHeight() - y_step * mTargets.size()) / 2 ) );

    for( auto &target : mTargets ) {
      gl::ScopedColor color( target._color );
      gl::drawSolidCircle( target._position, 25.0f );
      gl::translate( vec2( 0, y_step ) );
    }
  }

  gl::ScopedColor color( Color( CM_HSV, 0.575f, 1.0f, 1.0f ) );
  gl::translate( _position );
  gl::multModelMatrix( glm::eulerAngleYXZ( _rotation().y, _rotation().x, _rotation().z ) );
  gl::drawSolidCircle( vec2( 0 ), 30.0f );
}
<commit_msg>Grouping updates.<commit_after>/*
 * Copyright (c) 2014 David Wicks, sansumbrella.com
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or
 * without modification, are permitted provided that the following
 * conditions are met:
 *
 * Redistributions of source code must retain the above copyright
 * notice, this list of conditions and the following disclaimer.
 * Redistributions in binary form must reproduce the above copyright
 * notice, this list of conditions and the following disclaimer in the
 * documentation and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
 * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

#include "Loops.h"

using namespace choreograph;
using namespace cinder;

void Loops::setup()
{
  float left = 100.0f;
  float right = app::getWindowWidth() - left;
  PhraseRef<vec2> leftToRight = makeRamp( vec2( left, 0.0f ), vec2( right, 0.0f ), 1.0f, EaseInOutQuad() );

  //=====================================================
  // Looping Motions. Use for things that loop "forever."
  //=====================================================

  Output<vec2>  loopTarget;
  timeline().apply( &loopTarget, leftToRight )
    .finishFn( [] ( Motion<vec2> &m ) {
      m.resetTime();
    } );  // Motion should play forever.

  Output<vec2>  pingPongTarget;
  timeline().apply( &pingPongTarget, leftToRight )
    .finishFn( [] ( Motion<vec2> &m ) {
      // reverse Motion direction on finish.
      m.setPlaybackSpeed( m.getPlaybackSpeed() * -1 );
      // Start each cycle from "zero" to keep in sync with loopTarget timing.
      m.resetTime();
    } );

  Output<vec2>  pingPongSlowerTarget;
  timeline().apply( &pingPongSlowerTarget, leftToRight )
    .finishFn( [] ( Motion<vec2> &m ) {
      // Reverse and slow Motion on finish.
      m.setPlaybackSpeed( m.getPlaybackSpeed() * -0.9f );
      // If we're unbearably slow, stop looping.
      if( std::abs( m.getPlaybackSpeed() ) < 0.2f ) {
        m.finishFn( [] ( Motion<vec2> &m ) {} );
      }
      else {
        m.resetTime();
      }
    } );

  //==========================================================
  // Looping Motion Group. Use for separate motions that loop
  // with each other, but have different durations.
  //==========================================================

  SequenceRef<vec2> positionSequence = createSequence( vec2( app::getWindowSize() ) * vec2( 0.66, 1 ) + vec2( 0, 50 ) );
  SequenceRef<vec3> rotationSequence = createSequence( vec3( M_PI / 2, 0, 0 ) );

  rotationSequence->then<RampTo>( vec3( 4 * M_PI, 2 * M_PI, 0 ), 1.0f, EaseOutQuint() );
  positionSequence->then<RampTo>( vec2( app::getWindowSize() ) * vec2( 0.66, 0.5 ), 0.5f, EaseOutAtan() );

  auto group = std::make_shared<MotionGroup>();
  group->add( positionSequence, &_position );
  group->add( rotationSequence, &_rotation );
  // start grouped motions after a 0.5 second hold on their start values.
  group->setStartTime( 0.5f );
  group->setFinishFn( [] ( MotionGroup &group ) {
    group.setPlaybackSpeed( group.getPlaybackSpeed() * -1 );
    group.resetTime();
  } );

  timeline().add( group );

  //=====================================================
  // Looping Phrases. Use for a finite number of loops.
  //=====================================================

  Output<vec2> loopPhraseTarget;
  timeline().apply( &loopPhraseTarget ).then( makeRepeat( leftToRight, 7.5f ) );

  Output<vec2> pingPongPhraseTarget;
  timeline().apply( &pingPongPhraseTarget ).then( makePingPong( leftToRight, 7.5f ) );

  mTargets.push_back( { loopTarget, Color( 1, 0, 1 ) } );
  mTargets.push_back( { pingPongTarget, Color( 1, 0, 1 ) } );
  mTargets.push_back( { pingPongSlowerTarget, Color( 0, 1, 1 ) } );
  mTargets.push_back( { loopPhraseTarget, Color( 1, 1, 0 ) } );
  mTargets.push_back( { pingPongPhraseTarget, Color( 1, 1, 0 ) } );
}

void Loops::update( double dt )
{
  timeline().step( dt );
}

void Loops::draw()
{
  gl::ScopedModelMatrix matrix;
  gl::setMatricesWindowPersp( app::getWindowSize() );

  {
    gl::ScopedModelMatrix singleDotMatrix;

    const float y_step = 100.0f;
    gl::translate( vec2( 0, (app::getWindowHeight() - y_step * mTargets.size()) / 2 ) );

    for( auto &target : mTargets ) {
      gl::ScopedColor color( target._color );
      gl::drawSolidCircle( target._position, 24.0f );
      gl::translate( vec2( 0, y_step ) );
    }
  }

  gl::ScopedColor color( Color( CM_HSV, 0.575f, 1.0f, 1.0f ) );
  gl::translate( _position );
  gl::multModelMatrix( glm::eulerAngleYXZ( _rotation().y, _rotation().x, _rotation().z ) );
  gl::drawSolidCircle( vec2( 0 ), 36.0f );
}
<|endoftext|>


<commit_before>/**
 *  LFU
 *  ===
 *
 *  Cache: Least frequently used in O(1) time (if no map conflicts & rehashing).
 *
 *  head_                                     tail_
 *    |                                         |
 *    v                                         v
 *  | prev_; LinkedHashSet; next_; | | | | | | | |
 *
 *  Note: Compile with -std=c++11.
 */

#include <iostream>
#include <unordered_map>
#include <list>

template <typename K> class freq;

template <typename K>
class freq_node {
public:
    freq_node(int f, freq_node *prev, freq_node *next)
        : f_(f), prev_(prev), next_(next)  { /* nop */ }
    ~freq_node() { /* nop */ }

    // No copy and move.
    freq_node(const freq_node&) = delete;
    freq_node& operator=(const freq_node&) = delete;
    freq_node(freq_node&&) = delete;
    freq_node& operator=(freq_node&&) = delete;

    friend freq<K>;

    void
    add_key(K k)
    {
        kq_.emplace_back(k);
        auto it = kq_.end();
        if (!kq_.empty()) --it;
        kis_.emplace(k, it);
    }

    void
    remove_key(K k)
    {
        auto it = kis_[k];
        kis_.erase(k);
        kq_.erase(it);
    }

    void
    remove_last_key()
    {
        K k = kq_.front();
        kis_.erase(k);
        kq_.pop_front();
    }
private:
    int f_;
    freq_node<K> *prev_;
    freq_node<K> *next_;
    // list + unordered_map = LinkedHashSet in Java.
    std::list<K> kq_;
    std::unordered_map<K, typename std::list<K>::iterator> kis_;
};

template <typename K>
class freq {
public:
    freq() : head_(NULL), tail_(NULL) { /* nop */ };
    ~freq() { /* nop */ }

    // No copy and move.
    freq(const freq&) = delete;
    freq& operator=(const freq&) = delete;
    freq(freq&&) = delete;
    freq& operator=(freq&&) = delete;

    void
    add_last(K k)
    {
        if (tail_ == NULL) head_ = tail_ = new freq_node<K>(1, NULL, NULL);
        if (tail_->f_ != 1) {
            auto temp = new freq_node<K>(1, tail_, NULL);
            tail_->next_ = temp;
            tail_ = temp;
        }
        tail_->add_key(k);
        kfs_.emplace(k, tail_);
    }

    void
    inc(K k)
    {
        auto n = kfs_[k];
        n->remove_key(k);
        kfs_.erase(k);

        if (head_ == n) {
            auto temp = new freq_node<K>(n->f_ + 1, NULL, head_);
            head_->prev_ = temp;
            head_ = temp;
            kfs_.emplace(k, head_);
            head_->add_key(k);
        } else if (n->prev_->f_ != n->f_ + 1) {
            auto temp = new freq_node<K>(n->f_ + 1, n->prev_, n);
            n->prev_ = temp;
            n->prev_->next_ = temp;
            kfs_.emplace(k, temp);
            temp->add_key(k);
        } else {
            kfs_.emplace(k, n->prev_);
            n->prev_->add_key(k);
        }

        if (n->kq_.empty()) {
            if (n == tail_) {
                tail_ = n->prev_;
                tail_->next_ = NULL;
            } else {
                n->prev_->next_ = n->next_;
                n->next_->prev_ = n->prev_;
            }
            delete n;
        }
    }

    void
    remove_last()
    {
        if (tail_->kq_.size() > 1) tail_->remove_last_key();
        else {
            tail_ = tail_->prev_;
            delete tail_->next_;
            tail_->next_ = NULL;
        }
    }
private:
    freq_node<K> *head_;
    freq_node<K> *tail_;
    std::unordered_map<K, freq_node<K>*> kfs_;   // key-frequency store
};

template <typename K, typename V>
class lfu {
public:
    lfu() : capacity_(2) { /* nop */ }
    explicit lfu(int capacity) : capacity_(capacity) { /* nop */ }
    ~lfu() { /* nop */ }

    // No copy and move.
    lfu(const lfu&) = delete;
    lfu& operator=(const lfu&) = delete;
    lfu(lfu&&) = delete;
    lfu& operator=(lfu&&) = delete;

    unsigned size() const { return siz_; }

    V
    get(K k)
    {
        V v = kvs_[k];
        fq_.inc(k);
        return v;
    }

    void
    set(K k, V v)
    {
        auto q = kvs_.find(k);

        if (q == kvs_.end()) {
            fq_.add_last(k);
            kvs_.emplace(k, v);
        } else kvs_[k] = v;

        if (siz_ + 1 > capacity_) fq_.remove_last();
        else ++siz_;
    }
private:
    unsigned siz_{0};
    unsigned capacity_;
    std::unordered_map<K, V> kvs_;
    freq<K> fq_;
};

int
main(int argc, const char *argv[])
{
    lfu<int, int> cache{4};

    cache.set(1, 42);
    cache.set(2, 3);
    cache.set(3, 4);
    cache.set(4, 5);

    std::cout << cache.get(1) << std::endl;

    cache.set(5, 6);
    std::cout << cache.get(3) << std::endl;
    // std::cout << cache.get(2) << std::endl; // now {2: 3} has gone

    // cache.get(6);

    return 0;
}
<commit_msg>fixed lfu error handling<commit_after>/**
 *  LFU
 *  ===
 *
 *  Cache: Least frequently used in O(1) time (if no map conflicts & rehashing).
 *
 *  head_                                     tail_
 *    |                                         |
 *    v                                         v
 *  | prev_; LinkedHashSet; next_; | | | | | | | |
 *
 *  Note: Compile with -std=c++11.
 */

#include <iostream>
#include <unordered_map>
#include <list>

template <typename K> class freq;

template <typename K>
class freq_node {
public:
    freq_node(int f, freq_node *prev, freq_node *next)
        : f_(f), prev_(prev), next_(next)  { /* nop */ }
    ~freq_node() { /* nop */ }

    // No copy and move.
    freq_node(const freq_node&) = delete;
    freq_node& operator=(const freq_node&) = delete;
    freq_node(freq_node&&) = delete;
    freq_node& operator=(freq_node&&) = delete;

    friend freq<K>;

    void
    add_key(K k)
    {
        kq_.emplace_back(k);
        auto it = kq_.end();
        if (!kq_.empty()) --it;
        kis_.emplace(k, it);
    }

    void
    remove_key(K k)
    {
        auto it = kis_[k];
        kis_.erase(k);
        kq_.erase(it);
    }

    K
    remove_last_key()
    {
        K k = kq_.front();
        kis_.erase(k);
        kq_.pop_front();
        return k;
    }
private:
    int f_;
    freq_node<K> *prev_;
    freq_node<K> *next_;
    // list + unordered_map = LinkedHashSet in Java.
    std::list<K> kq_;
    std::unordered_map<K, typename std::list<K>::iterator> kis_;
};

template <typename K>
class freq {
public:
    freq() : head_(NULL), tail_(NULL) { /* nop */ };
    ~freq() { /* nop */ }

    // No copy and move.
    freq(const freq&) = delete;
    freq& operator=(const freq&) = delete;
    freq(freq&&) = delete;
    freq& operator=(freq&&) = delete;

    void
    add_last(K k)
    {
        if (head_ == NULL) head_ = tail_ = new freq_node<K>(1, NULL, NULL);
        if (tail_->f_ != 1) {
            auto temp = new freq_node<K>(1, tail_, NULL);
            tail_->next_ = temp;
            tail_ = temp;
        }
        tail_->add_key(k);
        kfs_.emplace(k, tail_);
    }

    void
    inc(K k)
    {
        auto n = kfs_[k];
        n->remove_key(k);
        kfs_.erase(k);

        if (head_ == n) {
            auto temp = new freq_node<K>(n->f_ + 1, NULL, head_);
            head_->prev_ = temp;
            head_ = temp;
            kfs_.emplace(k, head_);
            head_->add_key(k);
        } else if (n->prev_->f_ != n->f_ + 1) {
            auto temp = new freq_node<K>(n->f_ + 1, n->prev_, n);
            n->prev_ = temp;
            n->prev_->next_ = temp;
            kfs_.emplace(k, temp);
            temp->add_key(k);
        } else {
            kfs_.emplace(k, n->prev_);
            n->prev_->add_key(k);
        }

        if (n->kq_.empty()) {
            if (n == tail_) {
                tail_ = n->prev_;
                tail_->next_ = NULL;
            } else {
                n->prev_->next_ = n->next_;
                n->next_->prev_ = n->prev_;
            }
            delete n;
        }
    }

    K
    remove_last()
    {
        K k = tail_->remove_last_key();
        if (tail_->kq_.empty()) {
            tail_ = tail_->prev_;
            delete tail_->next_;
            tail_->next_ = NULL;
        }
        return k;
    }
private:
    freq_node<K> *head_;
    freq_node<K> *tail_;
    std::unordered_map<K, freq_node<K>*> kfs_;
};

template <typename K, typename V>
class lfu {
public:
    lfu() : capacity_(2) { /* nop */ }
    explicit lfu(int capacity) : capacity_(capacity) { /* nop */ }
    ~lfu() { /* nop */ }

    // No copy and move.
    lfu(const lfu&) = delete;
    lfu& operator=(const lfu&) = delete;
    lfu(lfu&&) = delete;
    lfu& operator=(lfu&&) = delete;

    unsigned size() const { return siz_; }

    V
    get(K k)
    {
        if (kvs_.find(k) == kvs_.end()) {
            throw std::runtime_error("key not found");
        } else {
            V v = kvs_[k];
            fq_.inc(k);
            return v;
        }
    }

    void
    set(K k, V v)
    {
        auto q = kvs_.find(k);

        if (q == kvs_.end()) {
            fq_.add_last(k);
            kvs_.emplace(k, v);
        } else kvs_[k] = v;

        if (siz_ + 1 > capacity_) {
            K k = fq_.remove_last();
            kvs_.erase(k);
        } else ++siz_;
    }
private:
    unsigned siz_{0};
    unsigned capacity_;
    std::unordered_map<K, V> kvs_;
    freq<K> fq_;
};

int
main(int argc, const char *argv[])
{
    lfu<int, int> cache{4};

    cache.set(1, 42);
    cache.set(2, 3);
    cache.set(3, 4);
    std::cout << "size=" << cache.size() << std::endl;
    cache.set(4, 5);
    std::cout << cache.get(1) << std::endl;

    cache.set(5, 6);
    try {
        std::cout << cache.get(2) << std::endl; // now {2: 3} has gone
    } catch (const std::exception& e) {
        std::cout << "key `2': " << e.what() << std::endl;
    }

    // Key simply not found.
    cache.get(6);

    return 0;
}
<|endoftext|>