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

#ifdef HAVE_CONFIG_H
#include "config.h"
#endif

#include "vaapi/vaapidisplay.h"
#include <stdint.h>
#include <unistd.h>
#include <fcntl.h>
#include <list>
#include "common/log.h"
#include "common/lock.h"
#include "vaapi/VaapiUtils.h"

using std::list;
/**
1. client and yami shares the same display when it provides both native
   display (x11 Display or drm fd) and display type in setNativeDisplay().
   client owns the native display
2. when client set native display type only, yami will create a native
   display and owns it.
3. when client doesn't set any native display, or set display type to
   NATIVE_DISPLAY_AUTO; yami will try to open a x11 display first. if fail,
   drm display will try next

4. A x11 display is compatible to drm display, while not reverse.
   it means, when there is a VADisplay created from x11 display already ,
   yami will not create a new display when drm display is requested,
   simplely reuse the VADisplay.
*/

//helper function
namespace YamiMediaCodec{
static bool vaInit(VADisplay vaDisplay)
{
   int majorVersion, minorVersion;
   VAStatus vaStatus;
   vaStatus= vaInitialize(vaDisplay, &majorVersion, &minorVersion);
   return checkVaapiStatus(vaStatus, "vaInitialize");
}

class NativeDisplayBase {
  public:
    NativeDisplayBase() :m_handle(0) { };
    virtual ~NativeDisplayBase() {};
    virtual bool initialize(const NativeDisplay& display) = 0;
    virtual bool isCompatible (const NativeDisplay& display) = 0;
    intptr_t nativeHandle() {return m_handle;};

  protected:
    virtual bool acceptValidExternalHandle(const NativeDisplay& display) {
        if (display.handle && display.handle != -1) {
            m_handle = display.handle;
            m_selfCreated = false;
            return true;
        }
        return false;
    }
    intptr_t m_handle;
    bool m_selfCreated;

  private:
    DISALLOW_COPY_AND_ASSIGN(NativeDisplayBase);
};

#if __ENABLE_X11__
class NativeDisplayX11 : public NativeDisplayBase{
  public:
    NativeDisplayX11() :NativeDisplayBase(){ };
    virtual ~NativeDisplayX11() {
        if (m_selfCreated && m_handle)
            XCloseDisplay((Display*)(m_handle));
    };

    virtual bool initialize (const NativeDisplay& display) {
        ASSERT(display.type == NATIVE_DISPLAY_X11 || display.type == NATIVE_DISPLAY_AUTO);

        if (acceptValidExternalHandle(display))
            return true;

        m_handle = (intptr_t)XOpenDisplay(NULL);
        m_selfCreated = true;
        return (Display*)m_handle != NULL;
    };

    virtual bool isCompatible(const NativeDisplay& display) {
        if (display.type == NATIVE_DISPLAY_DRM || display.type == NATIVE_DISPLAY_AUTO)
            return true; // x11 is compatile to any drm, (do not consider one X with 2 gfx device)
        if (display.type == NATIVE_DISPLAY_X11 && (!display.handle || display.handle == m_handle))
            return true;
        return false;
    }
};
#endif
class NativeDisplayDrm : public NativeDisplayBase{
  public:
    NativeDisplayDrm() :NativeDisplayBase(){ };
    virtual ~NativeDisplayDrm() {
        if (m_selfCreated && m_handle && m_handle != -1)
            ::close(m_handle);
    };
    virtual bool initialize (const NativeDisplay& display) {
        ASSERT(display.type == NATIVE_DISPLAY_DRM || display.type == NATIVE_DISPLAY_AUTO);

        if (acceptValidExternalHandle(display))
            return true;

        m_handle = open("/dev/dri/renderD128", O_RDWR);
        if (m_handle < 0)
            m_handle = open("/dev/dri/card0", O_RDWR);
        m_selfCreated = true;
        return m_handle != -1;
    };

    bool isCompatible(const NativeDisplay& display) {
        if (display.type != NATIVE_DISPLAY_DRM)
            return false;
        if (display.handle == 0 || display.handle == -1 || display.handle == m_handle)
            return true;
        return false;
    }
};

class NativeDisplayVADisplay : public NativeDisplayBase{
  public:
    NativeDisplayVADisplay() :NativeDisplayBase(){ };
    ~NativeDisplayVADisplay() {};
    virtual bool initialize (const NativeDisplay& display) {
        ASSERT(display.type == NATIVE_DISPLAY_VA);

        return acceptValidExternalHandle(display);
    };

    bool isCompatible(const NativeDisplay& display) {
        return display.type == NATIVE_DISPLAY_VA && display.handle == m_handle;
    }
};

typedef SharedPtr<NativeDisplayBase> NativeDisplayPtr;

bool VaapiDisplay::isCompatible(const NativeDisplay& other)
{
    return m_nativeDisplay->isCompatible(other);
}

VaapiDisplay::~VaapiDisplay()
{
    if (!DynamicPointerCast<NativeDisplayVADisplay>(m_nativeDisplay)) {
        vaTerminate(m_vaDisplay);
    }
}

bool VaapiDisplay::setRotation(int degree)
{
    VAStatus vaStatus;
    VADisplayAttribute* attrList = NULL;
    VADisplayAttribute rotate;
    int i, numAttributes;
    rotate.type = VADisplayAttribRotation;
    rotate.value = VA_ROTATION_NONE;
    if (degree == 0) //no need to set rotation when degree is zero
        return true;
    else if (degree == 90)
        rotate.value = VA_ROTATION_90;
    else if (degree == 180)
        rotate.value = VA_ROTATION_180;
    else if (degree == 270)
        rotate.value = VA_ROTATION_270;

    /* should query before set display attributres */
    vaStatus = vaQueryDisplayAttributes(m_vaDisplay, attrList, &numAttributes);
    if (!checkVaapiStatus(vaStatus, "vaQueryDisplayAttributes") || !attrList)
       return false;

    for (i = 0; i < numAttributes; i++) {
        if (attrList[i].type == VADisplayAttribRotation)
            break;
    }

    if ((i == numAttributes) || !(attrList[i].flags & VA_DISPLAY_ATTRIB_SETTABLE) )
        return false;

    vaStatus = vaSetDisplayAttributes(m_vaDisplay, &rotate, 1);
    if (!checkVaapiStatus(vaStatus, "vaSetDisplayAttributes"))
        return false;
    return true;

}

const VAImageFormat *
VaapiDisplay::getVaFormat(uint32_t fourcc)
{
    AutoLock locker(m_lock);
    size_t i;

    if (m_vaImageFormats.empty()) {
        VAStatus vaStatus;
        int numImageFormats;
        numImageFormats = vaMaxNumImageFormats(m_vaDisplay);
        if (numImageFormats == 0)
            return NULL;

        m_vaImageFormats.reserve(numImageFormats);
        m_vaImageFormats.resize(numImageFormats);

        vaStatus = vaQueryImageFormats(m_vaDisplay, &m_vaImageFormats[0], &numImageFormats);
        checkVaapiStatus(vaStatus, "vaQueryImageFormats()");
        for (i=0; i< m_vaImageFormats.size(); i++)
            DEBUG_FOURCC("supported image format: ", m_vaImageFormats[i].fourcc);
    }

    for (i = 0; i < m_vaImageFormats.size(); i++) {
        VAImageFormat vaImageFormat = m_vaImageFormats[i];
        if (vaImageFormat.fourcc == fourcc)
            return &m_vaImageFormats[i];
    }
    return NULL;
}

//display cache
class DisplayCache
{
public:
    static SharedPtr<DisplayCache> getInstance();
    DisplayPtr createDisplay(const NativeDisplay& nativeDisplay);

    ~DisplayCache() {}
private:
    DisplayCache() {}

    list<WeakPtr<VaapiDisplay> > m_cache;
    YamiMediaCodec::Lock m_lock;
};

SharedPtr<DisplayCache> DisplayCache::getInstance()
{
    static SharedPtr<DisplayCache> cache;
    if (!cache) {
        SharedPtr<DisplayCache> temp(new DisplayCache);
        cache = temp;
    }
    return cache;
}

bool expired(const WeakPtr<VaapiDisplay>& weak)
{
    return !weak.lock();
}

DisplayPtr DisplayCache::createDisplay(const NativeDisplay& nativeDisplay)
{
    NativeDisplayPtr nativeDisplayObj;
    VADisplay vaDisplay = NULL;
    DisplayPtr vaapiDisplay;
    YamiMediaCodec::AutoLock locker(m_lock);

    m_cache.remove_if(expired);

    //lockup first
    list<WeakPtr<VaapiDisplay> >::iterator it;
    for (it = m_cache.begin(); it != m_cache.end(); ++it) {
        vaapiDisplay = (*it).lock();
        if (vaapiDisplay->isCompatible(nativeDisplay)) {
            return vaapiDisplay;
        }
    }
    vaapiDisplay.reset();

    //crate new one
    DEBUG("nativeDisplay: (type : %d), (handle : %ld)", nativeDisplay.type, nativeDisplay.handle);

    switch (nativeDisplay.type) {
    case NATIVE_DISPLAY_AUTO:
#if __ENABLE_X11__
    case NATIVE_DISPLAY_X11:
        nativeDisplayObj.reset (new NativeDisplayX11());
        if (nativeDisplayObj && nativeDisplayObj->initialize(nativeDisplay))
            vaDisplay = vaGetDisplay((Display*)(nativeDisplayObj->nativeHandle()));
        if (vaDisplay)
            INFO("use vaapi x11 backend");
        if(vaDisplay || nativeDisplay.type == NATIVE_DISPLAY_X11)
            break;
        INFO("try to init va with x11 display (%p) but failed", (Display*)(nativeDisplayObj->nativeHandle()));
        // NATIVE_DISPLAY_AUTO continue, no break
#endif
    case NATIVE_DISPLAY_DRM:
        nativeDisplayObj.reset (new NativeDisplayDrm());
        if (nativeDisplayObj && nativeDisplayObj->initialize(nativeDisplay))
#ifndef ANDROID
            vaDisplay = vaGetDisplayDRM(nativeDisplayObj->nativeHandle());
#endif
        INFO("use vaapi drm backend");
        break;
    case NATIVE_DISPLAY_VA:
        nativeDisplayObj.reset (new NativeDisplayVADisplay());
        if (nativeDisplayObj && nativeDisplayObj->initialize(nativeDisplay))
            vaDisplay = (VADisplay)nativeDisplayObj->nativeHandle();
        INFO("use vaapi va backend");
        break;
    default:
        break;
    }

    if (vaDisplay == NULL) {
        ERROR("vaGetDisplay failed.");
        return vaapiDisplay;
    }

    if (nativeDisplay.type == NATIVE_DISPLAY_VA || vaInit(vaDisplay)) {
        DisplayPtr temp(new VaapiDisplay(nativeDisplayObj, vaDisplay));
        vaapiDisplay = temp;
    }
    if (vaapiDisplay) {
        WeakPtr<VaapiDisplay> weak(vaapiDisplay);
        m_cache.push_back(weak);
    }
    return vaapiDisplay;
}

DisplayPtr VaapiDisplay::create(const NativeDisplay& display)
{
    return DisplayCache::getInstance()->createDisplay(display);
}
} //YamiMediaCodec
<commit_msg>vaapi: fix x11/drm compatible problem<commit_after>/*
 * Copyright (C) 2014 Intel Corporation. All rights reserved.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#ifdef HAVE_CONFIG_H
#include "config.h"
#endif

#include "vaapi/vaapidisplay.h"
#include <stdint.h>
#include <unistd.h>
#include <fcntl.h>
#include <list>
#include "common/log.h"
#include "common/lock.h"
#include "vaapi/VaapiUtils.h"

using std::list;
/**
1. client and yami shares the same display when it provides both native
   display (x11 Display or drm fd) and display type in setNativeDisplay().
   client owns the native display
2. when client set native display type only, yami will create a native
   display and owns it.
3. when client doesn't set any native display, or set display type to
   NATIVE_DISPLAY_AUTO; yami will try to open a x11 display first. if fail,
   drm display will try next

4. A x11 display is compatible to drm display, while not reverse.
   it means, when there is a VADisplay created from x11 display already ,
   yami will not create a new display when drm display is requested,
   simplely reuse the VADisplay.
*/

//helper function
namespace YamiMediaCodec{
static bool vaInit(VADisplay vaDisplay)
{
   int majorVersion, minorVersion;
   VAStatus vaStatus;
   vaStatus= vaInitialize(vaDisplay, &majorVersion, &minorVersion);
   return checkVaapiStatus(vaStatus, "vaInitialize");
}

class NativeDisplayBase {
  public:
    NativeDisplayBase() :m_handle(0) { };
    virtual ~NativeDisplayBase() {};
    virtual bool initialize(const NativeDisplay& display) = 0;
    virtual bool isCompatible (const NativeDisplay& display) = 0;
    intptr_t nativeHandle() {return m_handle;};

  protected:
    virtual bool acceptValidExternalHandle(const NativeDisplay& display) {
        if (display.handle && display.handle != -1) {
            m_handle = display.handle;
            m_selfCreated = false;
            return true;
        }
        return false;
    }
    intptr_t m_handle;
    bool m_selfCreated;

  private:
    DISALLOW_COPY_AND_ASSIGN(NativeDisplayBase);
};

bool isInvalidDrmHandle(int handle)
{
    return handle == 0 || handle == -1;
}

#if __ENABLE_X11__
class NativeDisplayX11 : public NativeDisplayBase{
  public:
    NativeDisplayX11() :NativeDisplayBase(){ };
    virtual ~NativeDisplayX11() {
        if (m_selfCreated && m_handle)
            XCloseDisplay((Display*)(m_handle));
    };

    virtual bool initialize (const NativeDisplay& display) {
        ASSERT(display.type == NATIVE_DISPLAY_X11 || display.type == NATIVE_DISPLAY_AUTO);

        if (acceptValidExternalHandle(display))
            return true;

        m_handle = (intptr_t)XOpenDisplay(NULL);
        m_selfCreated = true;
        return (Display*)m_handle != NULL;
    };

    virtual bool isCompatible(const NativeDisplay& display) {
        if (display.type == NATIVE_DISPLAY_AUTO)
            return true;
        if (display.type == NATIVE_DISPLAY_DRM) {
            //invalid drm handle means any drm display is acceptable.
            if (isInvalidDrmHandle(display.handle))
                return true;
        }
        if (display.type == NATIVE_DISPLAY_X11 && (!display.handle || display.handle == m_handle))
            return true;
        return false;
    }
};
#endif
class NativeDisplayDrm : public NativeDisplayBase{
  public:
    NativeDisplayDrm() :NativeDisplayBase(){ };
    virtual ~NativeDisplayDrm() {
        if (m_selfCreated && m_handle && m_handle != -1)
            ::close(m_handle);
    };
    virtual bool initialize (const NativeDisplay& display) {
        ASSERT(display.type == NATIVE_DISPLAY_DRM || display.type == NATIVE_DISPLAY_AUTO);

        if (acceptValidExternalHandle(display))
            return true;

        m_handle = open("/dev/dri/renderD128", O_RDWR);
        if (m_handle < 0)
            m_handle = open("/dev/dri/card0", O_RDWR);
        m_selfCreated = true;
        return m_handle != -1;
    };

    bool isCompatible(const NativeDisplay& display) {
        if (display.type != NATIVE_DISPLAY_DRM)
            return false;
        if (isInvalidDrmHandle(display.handle) || display.handle == m_handle)
            return true;
        return false;
    }
};

class NativeDisplayVADisplay : public NativeDisplayBase{
  public:
    NativeDisplayVADisplay() :NativeDisplayBase(){ };
    ~NativeDisplayVADisplay() {};
    virtual bool initialize (const NativeDisplay& display) {
        ASSERT(display.type == NATIVE_DISPLAY_VA);

        return acceptValidExternalHandle(display);
    };

    bool isCompatible(const NativeDisplay& display) {
        return display.type == NATIVE_DISPLAY_VA && display.handle == m_handle;
    }
};

typedef SharedPtr<NativeDisplayBase> NativeDisplayPtr;

bool VaapiDisplay::isCompatible(const NativeDisplay& other)
{
    return m_nativeDisplay->isCompatible(other);
}

VaapiDisplay::~VaapiDisplay()
{
    if (!DynamicPointerCast<NativeDisplayVADisplay>(m_nativeDisplay)) {
        vaTerminate(m_vaDisplay);
    }
}

bool VaapiDisplay::setRotation(int degree)
{
    VAStatus vaStatus;
    VADisplayAttribute* attrList = NULL;
    VADisplayAttribute rotate;
    int i, numAttributes;
    rotate.type = VADisplayAttribRotation;
    rotate.value = VA_ROTATION_NONE;
    if (degree == 0) //no need to set rotation when degree is zero
        return true;
    else if (degree == 90)
        rotate.value = VA_ROTATION_90;
    else if (degree == 180)
        rotate.value = VA_ROTATION_180;
    else if (degree == 270)
        rotate.value = VA_ROTATION_270;

    /* should query before set display attributres */
    vaStatus = vaQueryDisplayAttributes(m_vaDisplay, attrList, &numAttributes);
    if (!checkVaapiStatus(vaStatus, "vaQueryDisplayAttributes") || !attrList)
       return false;

    for (i = 0; i < numAttributes; i++) {
        if (attrList[i].type == VADisplayAttribRotation)
            break;
    }

    if ((i == numAttributes) || !(attrList[i].flags & VA_DISPLAY_ATTRIB_SETTABLE) )
        return false;

    vaStatus = vaSetDisplayAttributes(m_vaDisplay, &rotate, 1);
    if (!checkVaapiStatus(vaStatus, "vaSetDisplayAttributes"))
        return false;
    return true;

}

const VAImageFormat *
VaapiDisplay::getVaFormat(uint32_t fourcc)
{
    AutoLock locker(m_lock);
    size_t i;

    if (m_vaImageFormats.empty()) {
        VAStatus vaStatus;
        int numImageFormats;
        numImageFormats = vaMaxNumImageFormats(m_vaDisplay);
        if (numImageFormats == 0)
            return NULL;

        m_vaImageFormats.reserve(numImageFormats);
        m_vaImageFormats.resize(numImageFormats);

        vaStatus = vaQueryImageFormats(m_vaDisplay, &m_vaImageFormats[0], &numImageFormats);
        checkVaapiStatus(vaStatus, "vaQueryImageFormats()");
        for (i=0; i< m_vaImageFormats.size(); i++)
            DEBUG_FOURCC("supported image format: ", m_vaImageFormats[i].fourcc);
    }

    for (i = 0; i < m_vaImageFormats.size(); i++) {
        VAImageFormat vaImageFormat = m_vaImageFormats[i];
        if (vaImageFormat.fourcc == fourcc)
            return &m_vaImageFormats[i];
    }
    return NULL;
}

//display cache
class DisplayCache
{
public:
    static SharedPtr<DisplayCache> getInstance();
    DisplayPtr createDisplay(const NativeDisplay& nativeDisplay);

    ~DisplayCache() {}
private:
    DisplayCache() {}

    list<WeakPtr<VaapiDisplay> > m_cache;
    YamiMediaCodec::Lock m_lock;
};

SharedPtr<DisplayCache> DisplayCache::getInstance()
{
    static SharedPtr<DisplayCache> cache;
    if (!cache) {
        SharedPtr<DisplayCache> temp(new DisplayCache);
        cache = temp;
    }
    return cache;
}

bool expired(const WeakPtr<VaapiDisplay>& weak)
{
    return !weak.lock();
}

DisplayPtr DisplayCache::createDisplay(const NativeDisplay& nativeDisplay)
{
    NativeDisplayPtr nativeDisplayObj;
    VADisplay vaDisplay = NULL;
    DisplayPtr vaapiDisplay;
    YamiMediaCodec::AutoLock locker(m_lock);

    m_cache.remove_if(expired);

    //lockup first
    list<WeakPtr<VaapiDisplay> >::iterator it;
    for (it = m_cache.begin(); it != m_cache.end(); ++it) {
        vaapiDisplay = (*it).lock();
        if (vaapiDisplay->isCompatible(nativeDisplay)) {
            return vaapiDisplay;
        }
    }
    vaapiDisplay.reset();

    //crate new one
    DEBUG("nativeDisplay: (type : %d), (handle : %ld)", nativeDisplay.type, nativeDisplay.handle);

    switch (nativeDisplay.type) {
    case NATIVE_DISPLAY_AUTO:
#if __ENABLE_X11__
    case NATIVE_DISPLAY_X11:
        nativeDisplayObj.reset (new NativeDisplayX11());
        if (nativeDisplayObj && nativeDisplayObj->initialize(nativeDisplay))
            vaDisplay = vaGetDisplay((Display*)(nativeDisplayObj->nativeHandle()));
        if (vaDisplay)
            INFO("use vaapi x11 backend");
        if(vaDisplay || nativeDisplay.type == NATIVE_DISPLAY_X11)
            break;
        INFO("try to init va with x11 display (%p) but failed", (Display*)(nativeDisplayObj->nativeHandle()));
        // NATIVE_DISPLAY_AUTO continue, no break
#endif
    case NATIVE_DISPLAY_DRM:
        nativeDisplayObj.reset (new NativeDisplayDrm());
        if (nativeDisplayObj && nativeDisplayObj->initialize(nativeDisplay))
#ifndef ANDROID
            vaDisplay = vaGetDisplayDRM(nativeDisplayObj->nativeHandle());
#endif
        INFO("use vaapi drm backend");
        break;
    case NATIVE_DISPLAY_VA:
        nativeDisplayObj.reset (new NativeDisplayVADisplay());
        if (nativeDisplayObj && nativeDisplayObj->initialize(nativeDisplay))
            vaDisplay = (VADisplay)nativeDisplayObj->nativeHandle();
        INFO("use vaapi va backend");
        break;
    default:
        break;
    }

    if (vaDisplay == NULL) {
        ERROR("vaGetDisplay failed.");
        return vaapiDisplay;
    }

    if (nativeDisplay.type == NATIVE_DISPLAY_VA || vaInit(vaDisplay)) {
        DisplayPtr temp(new VaapiDisplay(nativeDisplayObj, vaDisplay));
        vaapiDisplay = temp;
    }
    if (vaapiDisplay) {
        WeakPtr<VaapiDisplay> weak(vaapiDisplay);
        m_cache.push_back(weak);
    }
    return vaapiDisplay;
}

DisplayPtr VaapiDisplay::create(const NativeDisplay& display)
{
    return DisplayCache::getInstance()->createDisplay(display);
}
} //YamiMediaCodec
<|endoftext|>


<commit_before>/** \copyright
 * Copyright (c) 2015, 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 LPC1769 MCU.
 *
 * @author Stuart W. Baker
 * @date 12 April 2015
 */

#include <new>
#include <cstdint>

#include "chip.h"

#include "os/OS.hxx"
#include "Lpc17xx40xxUart.hxx"
#include "Lpc17xx40xxCan.hxx"
#include "Lpc17xx40xxGPIO.hxx"
#include "Lpc17xx40xxEEPROMEmulation.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";

/** UART 0 serial driver instance */
static LpcUart uart0("/dev/ser0", LPC_UART3, UART3_IRQn);

/** CAN 0 driver instance */
static LpcCan can0("/dev/can0", LPC_CAN2);

/** EEPROM file */
static LpcEEPROMEmulation eeprom("/dev/eeprom", 256);

extern "C" {
const uint32_t OscRateIn = 12000000;
const uint32_t RTCOscRateIn = 32768;

GPIO_PIN(LED0, LedPin, 0, 22);
GPIO_PIN(LED1, LedPin, 0,  2);
GPIO_PIN(LED2, LedPin, 0,  3);
GPIO_PIN(LED3, LedPin, 0, 21);

/* Pin muxing configuration */
STATIC const PINMUX_GRP_T pinmuxing[] = {
    {0,  0, IOCON_MODE_INACT  | IOCON_FUNC2},    /* TXD3 */
    {0,  1, IOCON_MODE_PULLUP | IOCON_FUNC2},    /* RXD3 */
    {0,  4, IOCON_MODE_INACT  | IOCON_FUNC2},    /* CAN-RD2 */
    {0,  5, IOCON_MODE_INACT  | IOCON_FUNC2},    /* CAN-TD2 */
    {0, 22, IOCON_MODE_INACT  | IOCON_FUNC0},    /* Led 0 */
    {0,  2, IOCON_MODE_INACT  | IOCON_FUNC0},    /* Led 1 J6.21 */
    {0,  3, IOCON_MODE_INACT  | IOCON_FUNC0},    /* Led 2 J6.22 */
    {0, 21, IOCON_MODE_INACT  | IOCON_FUNC0},    /* Led 3 J6.23 */
};

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

/** put hardware in a safe state.
 */
void hw_set_to_safe(void)
{
}

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

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

/** Interrupt handler for blinking LED.
 */
void timer3_interrupt_handler(void)
{
    //
    // Clear the timer interrupt.
    //
    Chip_TIMER_ClearMatch(LPC_TIMER3, 1);
    // Set output LED.
    Chip_GPIO_WritePortBit(LPC_GPIO, 0, 22, (rest_pattern & 1) ? true : false);

    // Shift and maybe reset pattern.
    rest_pattern >>= 1;
    if (!rest_pattern)
        rest_pattern = blinker_pattern;
}

/** Fault handler for assert.
 * @param pattern LED pattern for error
 */
void diewith(uint32_t pattern)
{
    vPortClearInterruptMask(0x20);
    asm("cpsie i\n");

    resetblink(pattern);
    while (1)
        ;
}

uint32_t clock_speed = 0;

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

    /* setup clock */
    Chip_SetupXtalClocking();
    Chip_SYSCTL_SetFLASHAccess(FLASHTIM_100MHZ_CPU);

    /* enable GPIO */
    Chip_GPIO_Init(LPC_GPIO);

    /* enable pinmux */
    Chip_IOCON_Init(LPC_IOCON);

    /* setup pinmuxing */
    Chip_IOCON_SetPinMuxing(LPC_IOCON, pinmuxing,
                            sizeof(pinmuxing) / sizeof(PINMUX_GRP_T));

    /* Setup LED as an output */
    LED0_Pin::hw_init();
    LED1_Pin::hw_init();
    LED2_Pin::hw_init();
    LED3_Pin::hw_init();
    setblink(0xFFFF0000);

    /* Blinker timer initialization */
    Chip_TIMER_Init(LPC_TIMER3);
    clock_speed = Chip_Clock_GetSystemClockRate();
    uint32_t timerFreq = Chip_Clock_GetSystemClockRate();
    Chip_TIMER_Reset(LPC_TIMER3);
    Chip_TIMER_MatchEnableInt(LPC_TIMER3, 1);
    Chip_TIMER_SetMatch(LPC_TIMER3, 1, (timerFreq / 8));
    Chip_TIMER_ResetOnMatchEnable(LPC_TIMER3, 1);
    Chip_TIMER_Enable(LPC_TIMER3);
    NVIC_ClearPendingIRQ(TIMER3_IRQn);
    NVIC_EnableIRQ(TIMER3_IRQn);
}

} /* extern "C" */
<commit_msg>Added sector size definition. Fixes https://github.com/bakerstu/openmrn/issues/50<commit_after>/** \copyright
 * Copyright (c) 2015, 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 LPC1769 MCU.
 *
 * @author Stuart W. Baker
 * @date 12 April 2015
 */

#include <new>
#include <cstdint>

#include "chip.h"

#include "os/OS.hxx"
#include "Lpc17xx40xxUart.hxx"
#include "Lpc17xx40xxCan.hxx"
#include "Lpc17xx40xxGPIO.hxx"
#include "Lpc17xx40xxEEPROMEmulation.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";

/** UART 0 serial driver instance */
static LpcUart uart0("/dev/ser0", LPC_UART3, UART3_IRQn);

/** CAN 0 driver instance */
static LpcCan can0("/dev/can0", LPC_CAN2);

/** Size of a FLASH sector on the device */
const size_t EEPROMEmulation::SECTOR_SIZE = 0x8000;

/** EEPROM file */
static LpcEEPROMEmulation eeprom("/dev/eeprom", 256);

extern "C" {
const uint32_t OscRateIn = 12000000;
const uint32_t RTCOscRateIn = 32768;

GPIO_PIN(LED0, LedPin, 0, 22);
GPIO_PIN(LED1, LedPin, 0,  2);
GPIO_PIN(LED2, LedPin, 0,  3);
GPIO_PIN(LED3, LedPin, 0, 21);

/* Pin muxing configuration */
STATIC const PINMUX_GRP_T pinmuxing[] = {
    {0,  0, IOCON_MODE_INACT  | IOCON_FUNC2},    /* TXD3 */
    {0,  1, IOCON_MODE_PULLUP | IOCON_FUNC2},    /* RXD3 */
    {0,  4, IOCON_MODE_INACT  | IOCON_FUNC2},    /* CAN-RD2 */
    {0,  5, IOCON_MODE_INACT  | IOCON_FUNC2},    /* CAN-TD2 */
    {0, 22, IOCON_MODE_INACT  | IOCON_FUNC0},    /* Led 0 */
    {0,  2, IOCON_MODE_INACT  | IOCON_FUNC0},    /* Led 1 J6.21 */
    {0,  3, IOCON_MODE_INACT  | IOCON_FUNC0},    /* Led 2 J6.22 */
    {0, 21, IOCON_MODE_INACT  | IOCON_FUNC0},    /* Led 3 J6.23 */
};

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

/** put hardware in a safe state.
 */
void hw_set_to_safe(void)
{
}

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

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

/** Interrupt handler for blinking LED.
 */
void timer3_interrupt_handler(void)
{
    //
    // Clear the timer interrupt.
    //
    Chip_TIMER_ClearMatch(LPC_TIMER3, 1);
    // Set output LED.
    Chip_GPIO_WritePortBit(LPC_GPIO, 0, 22, (rest_pattern & 1) ? true : false);

    // Shift and maybe reset pattern.
    rest_pattern >>= 1;
    if (!rest_pattern)
        rest_pattern = blinker_pattern;
}

/** Fault handler for assert.
 * @param pattern LED pattern for error
 */
void diewith(uint32_t pattern)
{
    vPortClearInterruptMask(0x20);
    asm("cpsie i\n");

    resetblink(pattern);
    while (1)
        ;
}

uint32_t clock_speed = 0;

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

    /* setup clock */
    Chip_SetupXtalClocking();
    Chip_SYSCTL_SetFLASHAccess(FLASHTIM_100MHZ_CPU);

    /* enable GPIO */
    Chip_GPIO_Init(LPC_GPIO);

    /* enable pinmux */
    Chip_IOCON_Init(LPC_IOCON);

    /* setup pinmuxing */
    Chip_IOCON_SetPinMuxing(LPC_IOCON, pinmuxing,
                            sizeof(pinmuxing) / sizeof(PINMUX_GRP_T));

    /* Setup LED as an output */
    LED0_Pin::hw_init();
    LED1_Pin::hw_init();
    LED2_Pin::hw_init();
    LED3_Pin::hw_init();
    setblink(0xFFFF0000);

    /* Blinker timer initialization */
    Chip_TIMER_Init(LPC_TIMER3);
    clock_speed = Chip_Clock_GetSystemClockRate();
    uint32_t timerFreq = Chip_Clock_GetSystemClockRate();
    Chip_TIMER_Reset(LPC_TIMER3);
    Chip_TIMER_MatchEnableInt(LPC_TIMER3, 1);
    Chip_TIMER_SetMatch(LPC_TIMER3, 1, (timerFreq / 8));
    Chip_TIMER_ResetOnMatchEnable(LPC_TIMER3, 1);
    Chip_TIMER_Enable(LPC_TIMER3);
    NVIC_ClearPendingIRQ(TIMER3_IRQn);
    NVIC_EnableIRQ(TIMER3_IRQn);
}

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


<commit_before>/*
 * Copyright (c) 2007-2009 Digital Bazaar, Inc. All rights reserved.
 */
#include "db/sql/sqlite3/Sqlite3Statement.h"

#include "db/rt/Thread.h"
#include "db/sql/sqlite3/Sqlite3Connection.h"
#include "db/sql/sqlite3/Sqlite3Row.h"

using namespace std;
using namespace db::sql;
using namespace db::sql::sqlite3;
using namespace db::rt;

Sqlite3Statement::Sqlite3Statement(Sqlite3Connection *c, const char* sql) :
   Statement(c, sql)
{
   // FIXME: switch to sqlite3_prepare_v2 when appropriate
   const char* tail;
   mState = sqlite3_prepare(c->getHandle(), sql, -1, &mHandle, &tail);
   if(mState != SQLITE_OK)
   {
      // exception
      ExceptionRef e = new Sqlite3Exception((Sqlite3Connection*)mConnection);
      e->getDetails()["sql"] = sql;
      Exception::setLast(e, false);
   }

   // no current row yet
   mRow = NULL;
}

Sqlite3Statement::~Sqlite3Statement()
{
   // clean up row, if any
   if(mRow != NULL)
   {
      delete mRow;
   }

   // clean up handle
   sqlite3_finalize(mHandle);
}

inline sqlite3_stmt* Sqlite3Statement::getHandle()
{
   return mHandle;
}

bool Sqlite3Statement::setInt32(unsigned int param, int32_t value)
{
   bool rval = true;

   mState = sqlite3_bind_int(mHandle, param, value);
   if(mState != SQLITE_OK)
   {
      // exception, could not bind parameter
      ExceptionRef e = new Sqlite3Exception((Sqlite3Connection*)mConnection);
      Exception::setLast(e, false);
      rval = false;
   }

   return rval;
}

bool Sqlite3Statement::setUInt32(unsigned int param, uint32_t value)
{
   bool rval = true;

   mState = sqlite3_bind_int(mHandle, param, value);
   if(mState != SQLITE_OK)
   {
      // exception, could not bind parameter
      ExceptionRef e = new Sqlite3Exception((Sqlite3Connection*)mConnection);
      Exception::setLast(e, false);
      rval = false;
   }

   return rval;
}

bool Sqlite3Statement::setInt64(unsigned int param, int64_t value)
{
   bool rval = true;

   mState = sqlite3_bind_int64(mHandle, param, value);
   if(mState != SQLITE_OK)
   {
      // exception, could not bind parameter
      ExceptionRef e = new Sqlite3Exception((Sqlite3Connection*)mConnection);
      Exception::setLast(e, false);
      rval = false;
   }

   return rval;
}

bool Sqlite3Statement::setUInt64(unsigned int param, uint64_t value)
{
   bool rval = true;

   mState = sqlite3_bind_int64(mHandle, param, value);
   if(mState != SQLITE_OK)
   {
      // exception, could not bind parameter
      ExceptionRef e = new Sqlite3Exception((Sqlite3Connection*)mConnection);
      Exception::setLast(e, false);
      rval = false;
   }

   return rval;
}

bool Sqlite3Statement::setText(unsigned int param, const char* value)
{
   bool rval = true;

   // use SQLITE_STATIC to ensure the memory is not cleaned up by sqlite
   mState = sqlite3_bind_text(mHandle, param, value, -1, SQLITE_STATIC);
   if(mState != SQLITE_OK)
   {
      // exception, could not bind parameter
      ExceptionRef e = new Sqlite3Exception((Sqlite3Connection*)mConnection);
      Exception::setLast(e, false);
      rval = false;
   }

   return rval;
}

bool Sqlite3Statement::setInt32(const char* name, int32_t value)
{
   bool rval = true;

   int index = getParameterIndex(name);
   if(index > 0)
   {
      rval = setInt32(index, value);
   }

   return rval;
}

bool Sqlite3Statement::setUInt32(const char* name, uint32_t value)
{
   bool rval = true;

   int index = getParameterIndex(name);
   if(index > 0)
   {
      rval = setUInt32(index, value);
   }

   return rval;
}

bool Sqlite3Statement::setInt64(const char* name, int64_t value)
{
   bool rval = true;

   int index = getParameterIndex(name);
   if(index > 0)
   {
      rval = setInt64(index, value);
   }

   return rval;
}

bool Sqlite3Statement::setUInt64(const char* name, uint64_t value)
{
   bool rval = true;

   int index = getParameterIndex(name);
   if(index > 0)
   {
      rval = setUInt64(index, value);
   }

   return rval;
}

bool Sqlite3Statement::setText(const char* name, const char* value)
{
   bool rval = true;

   int index = getParameterIndex(name);
   if(index > 0)
   {
      rval = setText(index, value);
   }

   return rval;
}

bool Sqlite3Statement::execute()
{
   bool rval = true;

   switch(mState)
   {
      case SQLITE_OK:
         // step to execute statement
         mState = sqlite3_step(mHandle);
         switch(mState)
         {
            case SQLITE_DONE:
            case SQLITE_ROW:
               // valid return state (done or got back a row)
               break;
            default:
            {
               // error stepping statement (version 1 of api requires reset)
               ExceptionRef e =
                  new Sqlite3Exception((Sqlite3Connection*)mConnection);
               Exception::setLast(e, false);
               rval = false;
               break;
            }
         }
         break;
      case SQLITE_DONE:
      case SQLITE_ROW:
      {
         // statement in bad state
         ExceptionRef e = new Exception(
            "Statement state is invalid. Did you call reset() to reuse "
            "the statement? (Connections should do this automatically).",
            "db.sql.sqlite3.BadState");
         Exception::setLast(e, false);
         rval = false;
         break;
      }
      default:
      {
         // driver error
         ExceptionRef e =
            new Sqlite3Exception((Sqlite3Connection*)mConnection);
         Exception::setLast(e, false);
         rval = false;
         break;
      }
   }

   return rval;
}

Row* Sqlite3Statement::fetch()
{
   Row* rval = NULL;

   if(mRow != NULL)
   {
      // get next row
      mState = sqlite3_step(mHandle);
      switch(mState)
      {
         case SQLITE_ROW:
            // return next row
            rval = mRow;
            break;
         case SQLITE_DONE:
            // no more rows, clean up row object
            delete mRow;
            mRow = NULL;
            break;
         default:
         {
            // error stepping statement (version 1 of api requires reset)
            ExceptionRef e =
               new Sqlite3Exception((Sqlite3Connection*)mConnection);
            Exception::setLast(e, false);
            reset();
            break;
         }
      }
   }
   else if(mState == SQLITE_ROW)
   {
      // create and return first row
      rval = mRow = new Sqlite3Row(this);
   }

   return rval;
}

bool Sqlite3Statement::reset()
{
   bool rval = true;

   // clean up existing row object
   if(mRow != NULL)
   {
      delete mRow;
      mRow = NULL;
   }

   // reset statement
   mState = sqlite3_reset(mHandle);
   if(mState != SQLITE_OK)
   {
      // driver error
      ExceptionRef e = new Sqlite3Exception((Sqlite3Connection*)mConnection);
      Exception::setLast(e, false);
      rval = false;
   }

   return rval;
}

bool Sqlite3Statement::getRowsChanged(uint64_t& rows)
{
   // FIXME: handle exceptions
   rows = sqlite3_changes(((Sqlite3Connection*)mConnection)->getHandle());
   return true;
}

uint64_t Sqlite3Statement::getLastInsertRowId()
{
   return sqlite3_last_insert_rowid(
      ((Sqlite3Connection*)mConnection)->getHandle());
}

int Sqlite3Statement::getParameterIndex(const char* name)
{
   int index = sqlite3_bind_parameter_index(mHandle, name);

   if(index == 0)
   {
      // exception, no parameter with given name found
      ExceptionRef e = new SqlException("Invalid parameter name.");
      e->getDetails()["name"] = name;
      Exception::setLast(e, false);
   }

   return index;
}
<commit_msg>Fixed inverted default rval bug.<commit_after>/*
 * Copyright (c) 2007-2009 Digital Bazaar, Inc. All rights reserved.
 */
#include "db/sql/sqlite3/Sqlite3Statement.h"

#include "db/rt/Thread.h"
#include "db/sql/sqlite3/Sqlite3Connection.h"
#include "db/sql/sqlite3/Sqlite3Row.h"

using namespace std;
using namespace db::sql;
using namespace db::sql::sqlite3;
using namespace db::rt;

Sqlite3Statement::Sqlite3Statement(Sqlite3Connection *c, const char* sql) :
   Statement(c, sql)
{
   // FIXME: switch to sqlite3_prepare_v2 when appropriate
   const char* tail;
   mState = sqlite3_prepare(c->getHandle(), sql, -1, &mHandle, &tail);
   if(mState != SQLITE_OK)
   {
      // exception
      ExceptionRef e = new Sqlite3Exception((Sqlite3Connection*)mConnection);
      e->getDetails()["sql"] = sql;
      Exception::setLast(e, false);
   }

   // no current row yet
   mRow = NULL;
}

Sqlite3Statement::~Sqlite3Statement()
{
   // clean up row, if any
   if(mRow != NULL)
   {
      delete mRow;
   }

   // clean up handle
   sqlite3_finalize(mHandle);
}

inline sqlite3_stmt* Sqlite3Statement::getHandle()
{
   return mHandle;
}

bool Sqlite3Statement::setInt32(unsigned int param, int32_t value)
{
   bool rval = true;

   mState = sqlite3_bind_int(mHandle, param, value);
   if(mState != SQLITE_OK)
   {
      // exception, could not bind parameter
      ExceptionRef e = new Sqlite3Exception((Sqlite3Connection*)mConnection);
      Exception::setLast(e, false);
      rval = false;
   }

   return rval;
}

bool Sqlite3Statement::setUInt32(unsigned int param, uint32_t value)
{
   bool rval = true;

   mState = sqlite3_bind_int(mHandle, param, value);
   if(mState != SQLITE_OK)
   {
      // exception, could not bind parameter
      ExceptionRef e = new Sqlite3Exception((Sqlite3Connection*)mConnection);
      Exception::setLast(e, false);
      rval = false;
   }

   return rval;
}

bool Sqlite3Statement::setInt64(unsigned int param, int64_t value)
{
   bool rval = true;

   mState = sqlite3_bind_int64(mHandle, param, value);
   if(mState != SQLITE_OK)
   {
      // exception, could not bind parameter
      ExceptionRef e = new Sqlite3Exception((Sqlite3Connection*)mConnection);
      Exception::setLast(e, false);
      rval = false;
   }

   return rval;
}

bool Sqlite3Statement::setUInt64(unsigned int param, uint64_t value)
{
   bool rval = true;

   mState = sqlite3_bind_int64(mHandle, param, value);
   if(mState != SQLITE_OK)
   {
      // exception, could not bind parameter
      ExceptionRef e = new Sqlite3Exception((Sqlite3Connection*)mConnection);
      Exception::setLast(e, false);
      rval = false;
   }

   return rval;
}

bool Sqlite3Statement::setText(unsigned int param, const char* value)
{
   bool rval = true;

   // use SQLITE_STATIC to ensure the memory is not cleaned up by sqlite
   mState = sqlite3_bind_text(mHandle, param, value, -1, SQLITE_STATIC);
   if(mState != SQLITE_OK)
   {
      // exception, could not bind parameter
      ExceptionRef e = new Sqlite3Exception((Sqlite3Connection*)mConnection);
      Exception::setLast(e, false);
      rval = false;
   }

   return rval;
}

bool Sqlite3Statement::setInt32(const char* name, int32_t value)
{
   bool rval = false;

   int index = getParameterIndex(name);
   if(index > 0)
   {
      rval = setInt32(index, value);
   }

   return rval;
}

bool Sqlite3Statement::setUInt32(const char* name, uint32_t value)
{
   bool rval = false;

   int index = getParameterIndex(name);
   if(index > 0)
   {
      rval = setUInt32(index, value);
   }

   return rval;
}

bool Sqlite3Statement::setInt64(const char* name, int64_t value)
{
   bool rval = false;

   int index = getParameterIndex(name);
   if(index > 0)
   {
      rval = setInt64(index, value);
   }

   return rval;
}

bool Sqlite3Statement::setUInt64(const char* name, uint64_t value)
{
   bool rval = false;

   int index = getParameterIndex(name);
   if(index > 0)
   {
      rval = setUInt64(index, value);
   }

   return rval;
}

bool Sqlite3Statement::setText(const char* name, const char* value)
{
   bool rval = false;

   int index = getParameterIndex(name);
   if(index > 0)
   {
      rval = setText(index, value);
   }

   return rval;
}

bool Sqlite3Statement::execute()
{
   bool rval = true;

   switch(mState)
   {
      case SQLITE_OK:
         // step to execute statement
         mState = sqlite3_step(mHandle);
         switch(mState)
         {
            case SQLITE_DONE:
            case SQLITE_ROW:
               // valid return state (done or got back a row)
               break;
            default:
            {
               // error stepping statement (version 1 of api requires reset)
               ExceptionRef e =
                  new Sqlite3Exception((Sqlite3Connection*)mConnection);
               Exception::setLast(e, false);
               rval = false;
               break;
            }
         }
         break;
      case SQLITE_DONE:
      case SQLITE_ROW:
      {
         // statement in bad state
         ExceptionRef e = new Exception(
            "Statement state is invalid. Did you call reset() to reuse "
            "the statement? (Connections should do this automatically).",
            "db.sql.sqlite3.BadState");
         Exception::setLast(e, false);
         rval = false;
         break;
      }
      default:
      {
         // driver error
         ExceptionRef e =
            new Sqlite3Exception((Sqlite3Connection*)mConnection);
         Exception::setLast(e, false);
         rval = false;
         break;
      }
   }

   return rval;
}

Row* Sqlite3Statement::fetch()
{
   Row* rval = NULL;

   if(mRow != NULL)
   {
      // get next row
      mState = sqlite3_step(mHandle);
      switch(mState)
      {
         case SQLITE_ROW:
            // return next row
            rval = mRow;
            break;
         case SQLITE_DONE:
            // no more rows, clean up row object
            delete mRow;
            mRow = NULL;
            break;
         default:
         {
            // error stepping statement (version 1 of api requires reset)
            ExceptionRef e =
               new Sqlite3Exception((Sqlite3Connection*)mConnection);
            Exception::setLast(e, false);
            reset();
            break;
         }
      }
   }
   else if(mState == SQLITE_ROW)
   {
      // create and return first row
      rval = mRow = new Sqlite3Row(this);
   }

   return rval;
}

bool Sqlite3Statement::reset()
{
   bool rval = true;

   // clean up existing row object
   if(mRow != NULL)
   {
      delete mRow;
      mRow = NULL;
   }

   // reset statement
   mState = sqlite3_reset(mHandle);
   if(mState != SQLITE_OK)
   {
      // driver error
      ExceptionRef e = new Sqlite3Exception((Sqlite3Connection*)mConnection);
      Exception::setLast(e, false);
      rval = false;
   }

   return rval;
}

bool Sqlite3Statement::getRowsChanged(uint64_t& rows)
{
   // FIXME: handle exceptions
   rows = sqlite3_changes(((Sqlite3Connection*)mConnection)->getHandle());
   return true;
}

uint64_t Sqlite3Statement::getLastInsertRowId()
{
   return sqlite3_last_insert_rowid(
      ((Sqlite3Connection*)mConnection)->getHandle());
}

int Sqlite3Statement::getParameterIndex(const char* name)
{
   int index = sqlite3_bind_parameter_index(mHandle, name);
   if(index == 0)
   {
      // exception, no parameter with given name found (index=0 is invalid)
      ExceptionRef e = new SqlException("Invalid parameter name.");
      e->getDetails()["name"] = name;
      Exception::setLast(e, false);
   }

   return index;
}
<|endoftext|>


<commit_before>//Example of the various methods of interpolation provided by the
// ROOT::Math::Interpolator class
//
//Example can also be run in ROOT by doing :
//
// root> .x testInterpolation.cxx
//
#include "TGraph.h"
#include "TAxis.h"
#include "TCanvas.h"
#include "TLegend.h"
#include "TApplication.h"
#include "TList.h"
#include "Math/Interpolator.h"
#include <iostream>
#include <string>
#include <cstdlib>

#include <cmath>

bool showGraphics = true;

TGraph *grorig = 0;

void interpolate( const  ROOT::Math::Interpolator & itp, bool drawSame = false ) {

   std::string type = itp.Type();
   std::cout << "\n" << type << "  interpolation:" << std::endl;

   std::cout << "x[i]     y[i]     deriv[i]     deriv2[i]    integral[i] \n" << std::endl;
   // print result of interpolation
   const Int_t n = 50;  //JH replacing n = 51;
   Int_t i = 0;
   double xi = 0.;
   Float_t xcoord[n], ycoord[n];

   for ( i = 0; i < 50; ++i) {
      xi = 0.2 * i;
      // JH replacing for ( double xi = 0; xi < 10.01; xi += 0.2) {
      xcoord[i] = xi;
      ycoord[i] = itp.Eval(xi);
      double dyi = itp.Deriv(xi);
      double dy2i = itp.Deriv2(xi);
      double igyi = itp.Integ(0, xi);
      std::cout << xcoord[i]  << "  " << ycoord[i] << "  " << dyi << "  " << dy2i << "  " <<  igyi << std::endl;
   }

   if (showGraphics) {
      TGraph *gr = new TGraph(n,xcoord,ycoord);
      gr->SetMarkerColor(kBlue);
      if (drawSame)     gr->SetMarkerColor(kGreen);
      gr->SetMarkerStyle(7);
      gr->Draw("CP");
      if (!drawSame) {
         TLegend * l = new TLegend(0.1,0.7,0.4,0.9);
         l->SetName("legend");
         l->AddEntry(grorig,"original data");
         l->AddEntry(gr,type.c_str());
         l->Draw();
      }
      else if (gPad) {
         TLegend * l = (TLegend*)  gPad->GetListOfPrimitives()->FindObject("legend");
         if (l) {
            l->AddEntry(gr, type.c_str() );
            l->Draw();
         }
      }
   }
   if (gPad) gPad->Update();

   return;

}

void testInterpolation() {

   // Create data
   int n = 10;
   Float_t xorig[11], yorig[11];
   std::vector<double> x(n+1);
   std::vector<double> y(n+1);
   for (int i = 0; i < n+1; ++i) {
      x[i] = i + 0.5 * std::sin(i+0.0);
      y[i] = i + std::cos(i * i+0.0);
      xorig[i] = x[i];
      yorig[i] = y[i];
   }

   TCanvas *c1 = 0;
   if (showGraphics) {
      c1 = new TCanvas("c1","Original (red), Linear (upper left), Polynomial (upper right), Spline , Spline periodic, Akima (lower left) and Akima Periodic (lower right) Interpolation",10,10,1000,800);
      c1->Divide(2,3);
      c1->cd(1);
   }

   grorig = new TGraph(n+1,xorig,yorig);
   grorig->SetMarkerColor(kRed);
   grorig->SetMarkerStyle(20);
   grorig->GetYaxis()->SetRange(0,40);
   grorig->Draw("AP");

   //ROOT::Math::Interpolator itp1(x, y, ROOT::Math::Interpolation::kLINEAR);
   ROOT::Math::Interpolator itp1(x.size(), ROOT::Math::Interpolation::kLINEAR);
   itp1.SetData(x,y);
   interpolate(itp1);

   if (showGraphics) {
      c1->cd(2);
      grorig->Draw("AP");
   }

   ROOT::Math::Interpolator itp2(x, y, ROOT::Math::Interpolation::kPOLYNOMIAL);
   interpolate(itp2);

   if (showGraphics) {
      c1->cd(3);
      grorig->Draw("AP");
   }

   //std::cout << "Cubic Spline Interpolation: " << std::endl;
   ROOT::Math::Interpolator itp3( 2*x.size(), ROOT::Math::Interpolation::kCSPLINE);
   itp3.SetData(x.size(), &x[0], &y[0]);
   interpolate(itp3);

   if (showGraphics) {
      c1->cd(4);
      grorig->Draw("AP");
   }

   //std::cout << "Akima  Interpolation: " << std::endl;
   ROOT::Math::Interpolator itp4(x, y, ROOT::Math::Interpolation::kAKIMA);
   interpolate(itp4);

   if (showGraphics) {
      c1->cd(5);
      grorig->Draw("AP");
   }

   //std::cout << "Cubic Spline Periodic Interpolation: " << std::endl;
   ROOT::Math::Interpolator itp5(x, y, ROOT::Math::Interpolation::kCSPLINE_PERIODIC);
   interpolate(itp5);

   if (showGraphics) {
      c1->cd(6);
      grorig->Draw("AP");
   }

   //std::cout << "Akima Periodic Interpolation: " << std::endl;
   ROOT::Math::Interpolator itp6(x, y, ROOT::Math::Interpolation::kAKIMA_PERIODIC);
   interpolate(itp6);

   std::cout << "\n***********************************" << std::endl;
   std::cout << "Using default Interpolation type: " << std::endl;

   ROOT::Math::Interpolator itp7;
   itp7.SetData(x,y);
   interpolate(itp7,true);

}

#ifndef __CINT__
int main(int argc, char **argv)
{
   using std::cerr;
   using std::cout;
   using std::endl;
   showGraphics = false;

  // Parse command line arguments
  for (Int_t i=1 ;  i<argc ; i++) {
     std::string arg = argv[i] ;
     if (arg == "-g") {
      showGraphics = true;
     }
     if (arg == "-v") {
      showGraphics = true;
      //verbose = true;
     }
     if (arg == "-h") {
        cerr << "Usage: " << argv[0] << " [-g] [-v]\n";
        cerr << "  where:\n";
        cerr << "     -g : graphics mode\n";
        cerr << "     -v : verbose  mode";
        cerr << endl;
        return -1;
     }
   }

   TApplication* theApp = 0;

   if ( showGraphics )
      theApp = new TApplication("App",&argc,argv);

   testInterpolation();

   if ( showGraphics )
   {
      theApp->Run();
      delete theApp;
      theApp = 0;
   }

   return 0;
}
#endif
<commit_msg>removed duplicate increment in for loop<commit_after>//Example of the various methods of interpolation provided by the
// ROOT::Math::Interpolator class
//
//Example can also be run in ROOT by doing :
//
// root> .x testInterpolation.cxx
//
#include "TGraph.h"
#include "TAxis.h"
#include "TCanvas.h"
#include "TLegend.h"
#include "TApplication.h"
#include "TList.h"
#include "Math/Interpolator.h"
#include <iostream>
#include <string>
#include <cstdlib>

#include <cmath>

bool showGraphics = true;

TGraph *grorig = 0;

void interpolate( const  ROOT::Math::Interpolator & itp, bool drawSame = false ) {

   std::string type = itp.Type();
   std::cout << "\n" << type << "  interpolation:" << std::endl;

   std::cout << "x[i]     y[i]     deriv[i]     deriv2[i]    integral[i] \n" << std::endl;
   // print result of interpolation
   const Int_t n = 50;  //JH replacing n = 51;
   Int_t i = 0;
   Float_t xcoord[n], ycoord[n];

   for ( i = 0; i < n; ++i) {
      xi = 0.2 * i;
      // JH replacing for ( double xi = 0; xi < 10.01; xi += 0.2) {
      xcoord[i] = xi;
      ycoord[i] = itp.Eval(xi);
      double dyi = itp.Deriv(xi);
      double dy2i = itp.Deriv2(xi);
      double igyi = itp.Integ(0, xi);
      std::cout << xcoord[i]  << "  " << ycoord[i] << "  " << dyi << "  " << dy2i << "  " <<  igyi << std::endl;
   }

   if (showGraphics) {
      TGraph *gr = new TGraph(n,xcoord,ycoord);
      gr->SetMarkerColor(kBlue);
      if (drawSame)     gr->SetMarkerColor(kGreen);
      gr->SetMarkerStyle(7);
      gr->Draw("CP");
      if (!drawSame) {
         TLegend * l = new TLegend(0.1,0.7,0.4,0.9);
         l->SetName("legend");
         l->AddEntry(grorig,"original data");
         l->AddEntry(gr,type.c_str());
         l->Draw();
      }
      else if (gPad) {
         TLegend * l = (TLegend*)  gPad->GetListOfPrimitives()->FindObject("legend");
         if (l) {
            l->AddEntry(gr, type.c_str() );
            l->Draw();
         }
      }
   }
   if (gPad) gPad->Update();

   return;

}

void testInterpolation() {

   // Create data
   int n = 10;
   Float_t xorig[11], yorig[11];
   std::vector<double> x(n+1);
   std::vector<double> y(n+1);
   for (int i = 0; i < n+1; ++i) {
      x[i] = i + 0.5 * std::sin(i+0.0);
      y[i] = i + std::cos(i * i+0.0);
      xorig[i] = x[i];
      yorig[i] = y[i];
   }

   TCanvas *c1 = 0;
   if (showGraphics) {
      c1 = new TCanvas("c1","Original (red), Linear (upper left), Polynomial (upper right), Spline , Spline periodic, Akima (lower left) and Akima Periodic (lower right) Interpolation",10,10,1000,800);
      c1->Divide(2,3);
      c1->cd(1);
   }

   grorig = new TGraph(n+1,xorig,yorig);
   grorig->SetMarkerColor(kRed);
   grorig->SetMarkerStyle(20);
   grorig->GetYaxis()->SetRange(0,40);
   grorig->Draw("AP");

   //ROOT::Math::Interpolator itp1(x, y, ROOT::Math::Interpolation::kLINEAR);
   ROOT::Math::Interpolator itp1(x.size(), ROOT::Math::Interpolation::kLINEAR);
   itp1.SetData(x,y);
   interpolate(itp1);

   if (showGraphics) {
      c1->cd(2);
      grorig->Draw("AP");
   }

   ROOT::Math::Interpolator itp2(x, y, ROOT::Math::Interpolation::kPOLYNOMIAL);
   interpolate(itp2);

   if (showGraphics) {
      c1->cd(3);
      grorig->Draw("AP");
   }

   //std::cout << "Cubic Spline Interpolation: " << std::endl;
   ROOT::Math::Interpolator itp3( 2*x.size(), ROOT::Math::Interpolation::kCSPLINE);
   itp3.SetData(x.size(), &x[0], &y[0]);
   interpolate(itp3);

   if (showGraphics) {
      c1->cd(4);
      grorig->Draw("AP");
   }

   //std::cout << "Akima  Interpolation: " << std::endl;
   ROOT::Math::Interpolator itp4(x, y, ROOT::Math::Interpolation::kAKIMA);
   interpolate(itp4);

   if (showGraphics) {
      c1->cd(5);
      grorig->Draw("AP");
   }

   //std::cout << "Cubic Spline Periodic Interpolation: " << std::endl;
   ROOT::Math::Interpolator itp5(x, y, ROOT::Math::Interpolation::kCSPLINE_PERIODIC);
   interpolate(itp5);

   if (showGraphics) {
      c1->cd(6);
      grorig->Draw("AP");
   }

   //std::cout << "Akima Periodic Interpolation: " << std::endl;
   ROOT::Math::Interpolator itp6(x, y, ROOT::Math::Interpolation::kAKIMA_PERIODIC);
   interpolate(itp6);

   std::cout << "\n***********************************" << std::endl;
   std::cout << "Using default Interpolation type: " << std::endl;

   ROOT::Math::Interpolator itp7;
   itp7.SetData(x,y);
   interpolate(itp7,true);

}

#ifndef __CINT__
int main(int argc, char **argv)
{
   using std::cerr;
   using std::cout;
   using std::endl;
   showGraphics = false;

  // Parse command line arguments
  for (Int_t i=1 ;  i<argc ; i++) {
     std::string arg = argv[i] ;
     if (arg == "-g") {
      showGraphics = true;
     }
     if (arg == "-v") {
      showGraphics = true;
      //verbose = true;
     }
     if (arg == "-h") {
        cerr << "Usage: " << argv[0] << " [-g] [-v]\n";
        cerr << "  where:\n";
        cerr << "     -g : graphics mode\n";
        cerr << "     -v : verbose  mode";
        cerr << endl;
        return -1;
     }
   }

   TApplication* theApp = 0;

   if ( showGraphics )
      theApp = new TApplication("App",&argc,argv);

   testInterpolation();

   if ( showGraphics )
   {
      theApp->Run();
      delete theApp;
      theApp = 0;
   }

   return 0;
}
#endif
<|endoftext|>


<commit_before>/*
 * eos - A 3D Morphable Model fitting library written in modern C++11/14.
 *
 * File: matlab/+eos/+fitting/private/fitting.cpp
 *
 * Copyright 2016-2018 Patrik Huber
 *
 * 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 "eos/fitting/fitting.hpp"
#include "eos/core/LandmarkMapper.hpp"
#include "eos/core/Mesh.hpp"
#include "eos/fitting/RenderingParameters.hpp"
#include "eos/fitting/contour_correspondence.hpp"
#include "eos/morphablemodel/Blendshape.hpp"
#include "eos/morphablemodel/EdgeTopology.hpp"
#include "eos/morphablemodel/MorphableModel.hpp"
#include "eos/cpp17/optional.hpp"

#include "mexplus_eigen.hpp"
#include "mexplus_eos_types.hpp"

#include "mexplus.h"

#include "Eigen/Core"

#include "mex.h"

#include <string>

void mexFunction(int nlhs, mxArray* plhs[], int nrhs, const mxArray* prhs[])
{
    using std::string;
    using namespace eos;
    using namespace mexplus;

    // Check for proper number of input and output arguments:
    int num_input_args = 12;
    int num_output_args = 2;
    if (nrhs != num_input_args)
    {
        mexErrMsgIdAndTxt("eos:fitting:nargin", "fit_shape_and_pose requires 12 input arguments.");
    }
    if (nlhs != num_output_args)
    {
        mexErrMsgIdAndTxt("eos:fitting:nargout", "fit_shape_and_pose returns two output arguments.");
    }

    InputArguments input(nrhs, prhs, num_input_args);
    const auto morphablemodel_file = input.get<string>(0);
    const auto blendshapes_file = input.get<string>(1);
    const auto landmarks_in = input.get<Eigen::MatrixXd>(2);
    const auto mapper_file = input.get<string>(3);
    const auto image_width = input.get<int>(4);
    const auto image_height = input.get<int>(5);
    const auto edgetopo_file = input.get<string>(6);
    const auto contour_lms_file = input.get<string>(7);
    const auto model_cnt_file = input.get<string>(8);
    const auto num_iterations = input.get<int>(9);
    const auto num_shape_coeffs = input.get<int>(10);
    const auto lambda = input.get<double>(11);

    if (landmarks_in.rows() != 68)
    {
        mexErrMsgIdAndTxt(
            "eos:fitting:argin",
            "Given landmarks must be a 68 x 2 vector with ibug landmarks, in the order from 1 to 68.");
    }
    // Convert the landmarks (given as matrix in Matlab) to a LandmarkCollection:
    core::LandmarkCollection<Eigen::Vector2f> landmarks;
    for (int i = 0; i < 68; ++i)
    {
        landmarks.push_back(core::Landmark<Eigen::Vector2f>{
            std::to_string(i + 1), Eigen::Vector2f(landmarks_in(i, 0), landmarks_in(i, 1))});
    }

    // Load everything:
    const auto morphable_model = morphablemodel::load_model(morphablemodel_file);
    const auto blendshapes = morphablemodel::load_blendshapes(blendshapes_file);
    const core::LandmarkMapper landmark_mapper(mapper_file);
    const auto edge_topology = morphablemodel::load_edge_topology(edgetopo_file);
    const auto contour_landmarks = fitting::ContourLandmarks::load(contour_lms_file);
    const auto model_contour = fitting::ModelContour::load(model_cnt_file);
    const cpp17::optional<int> num_shape_coefficients_to_fit =
        num_shape_coeffs == -1 ? cpp17::nullopt : cpp17::optional<int>(num_shape_coeffs);

    // Now do the actual fitting:
    core::Mesh mesh;
    fitting::RenderingParameters rendering_parameters;
    std::tie(mesh, rendering_parameters) = fitting::fit_shape_and_pose(
        morphable_model, blendshapes, landmarks, landmark_mapper, image_width, image_height, edge_topology,
        contour_landmarks, model_contour, num_iterations, num_shape_coefficients_to_fit, lambda);

    // Return the mesh and the rendering_parameters:
    OutputArguments output(nlhs, plhs, num_output_args);
    output.set(0, mesh);
    output.set(1, rendering_parameters);
};
<commit_msg>Check for correct number of cols in landmarks_in in Matlab bindings<commit_after>/*
 * eos - A 3D Morphable Model fitting library written in modern C++11/14.
 *
 * File: matlab/+eos/+fitting/private/fitting.cpp
 *
 * Copyright 2016-2018 Patrik Huber
 *
 * 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 "eos/fitting/fitting.hpp"
#include "eos/core/LandmarkMapper.hpp"
#include "eos/core/Mesh.hpp"
#include "eos/fitting/RenderingParameters.hpp"
#include "eos/fitting/contour_correspondence.hpp"
#include "eos/morphablemodel/Blendshape.hpp"
#include "eos/morphablemodel/EdgeTopology.hpp"
#include "eos/morphablemodel/MorphableModel.hpp"
#include "eos/cpp17/optional.hpp"

#include "mexplus_eigen.hpp"
#include "mexplus_eos_types.hpp"

#include "mexplus.h"

#include "Eigen/Core"

#include "mex.h"

#include <string>

void mexFunction(int nlhs, mxArray* plhs[], int nrhs, const mxArray* prhs[])
{
    using std::string;
    using namespace eos;
    using namespace mexplus;

    // Check for proper number of input and output arguments:
    int num_input_args = 12;
    int num_output_args = 2;
    if (nrhs != num_input_args)
    {
        mexErrMsgIdAndTxt("eos:fitting:nargin", "fit_shape_and_pose requires 12 input arguments.");
    }
    if (nlhs != num_output_args)
    {
        mexErrMsgIdAndTxt("eos:fitting:nargout", "fit_shape_and_pose returns two output arguments.");
    }

    InputArguments input(nrhs, prhs, num_input_args);
    const auto morphablemodel_file = input.get<string>(0);
    const auto blendshapes_file = input.get<string>(1);
    const auto landmarks_in = input.get<Eigen::MatrixXd>(2);
    const auto mapper_file = input.get<string>(3);
    const auto image_width = input.get<int>(4);
    const auto image_height = input.get<int>(5);
    const auto edgetopo_file = input.get<string>(6);
    const auto contour_lms_file = input.get<string>(7);
    const auto model_cnt_file = input.get<string>(8);
    const auto num_iterations = input.get<int>(9);
    const auto num_shape_coeffs = input.get<int>(10);
    const auto lambda = input.get<double>(11);

    if (landmarks_in.rows() != 68 || landmarks_in.cols() != 2)
    {
        mexErrMsgIdAndTxt(
            "eos:fitting:argin",
            "Given landmarks must be a 68 x 2 vector with ibug landmarks, in the order from 1 to 68.");
    }
    // Convert the landmarks (given as matrix in Matlab) to a LandmarkCollection:
    core::LandmarkCollection<Eigen::Vector2f> landmarks;
    for (int i = 0; i < 68; ++i)
    {
        landmarks.push_back(core::Landmark<Eigen::Vector2f>{
            std::to_string(i + 1), Eigen::Vector2f(landmarks_in(i, 0), landmarks_in(i, 1))});
    }

    // Load everything:
    const auto morphable_model = morphablemodel::load_model(morphablemodel_file);
    const auto blendshapes = morphablemodel::load_blendshapes(blendshapes_file);
    const core::LandmarkMapper landmark_mapper(mapper_file);
    const auto edge_topology = morphablemodel::load_edge_topology(edgetopo_file);
    const auto contour_landmarks = fitting::ContourLandmarks::load(contour_lms_file);
    const auto model_contour = fitting::ModelContour::load(model_cnt_file);
    const cpp17::optional<int> num_shape_coefficients_to_fit =
        num_shape_coeffs == -1 ? cpp17::nullopt : cpp17::optional<int>(num_shape_coeffs);

    // Now do the actual fitting:
    core::Mesh mesh;
    fitting::RenderingParameters rendering_parameters;
    std::tie(mesh, rendering_parameters) = fitting::fit_shape_and_pose(
        morphable_model, blendshapes, landmarks, landmark_mapper, image_width, image_height, edge_topology,
        contour_landmarks, model_contour, num_iterations, num_shape_coefficients_to_fit, lambda);

    // Return the mesh and the rendering_parameters:
    OutputArguments output(nlhs, plhs, num_output_args);
    output.set(0, mesh);
    output.set(1, rendering_parameters);
};
<|endoftext|>


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

   The MIT License

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

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

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

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

#include <Python.h>
#include <boost/python.hpp>

#include <gtest/gtest.h>
#include <Testing/ModuleTestBase/ModuleTestBase.h>
#include <Core/Python/PythonDatatypeConverter.h>
#include <Core/Datatypes/Legacy/Field/FieldInformation.h>
#include <Core/Matlab/matlabconverter.h>
#include <Core/Datatypes/Legacy/Field/VMesh.h>
#include <Testing/Utils/MatrixTestUtilities.h>
#include <Testing/Utils/SCIRunUnitTests.h>
#include <Testing/Utils/SCIRunFieldSamples.h>
#ifdef WIN32
#ifndef DEBUG
#include <Core/Python/PythonInterpreter.h>
#endif
#endif

using namespace SCIRun;
using namespace SCIRun::Core;
using namespace Core::Python;
using namespace Testing;
using namespace TestUtils;

class FieldConversionTests : public testing::Test
{
protected:
  virtual void SetUp() override
  {
  #ifdef WIN32
  #ifndef DEBUG
    PythonInterpreter::Instance().initialize(false, "Core_Python_Tests", boost::filesystem::current_path().string());
    PythonInterpreter::Instance().run_string("import SCIRunPythonAPI; from SCIRunPythonAPI import *");
  #endif
  #else
    Py_Initialize();
  #endif
  }

  static FieldHandle roundTripThroughMatlabConverter(FieldHandle field)
  {
    MatlabIO::matlabarray ma;
    {
      MatlabIO::matlabconverter mc(nullptr);
      mc.converttostructmatrix();
      mc.sciFieldTOmlArray(field, ma);
    }

    FieldHandle actual;
    {
      MatlabIO::matlabconverter mc(nullptr);
      mc.mlArrayTOsciField(ma, actual);
    }
    return actual;
  }

  static FieldHandle TetMesh1()
  {
    return loadFieldFromFile(TestResources::rootDir() / "Fields/test_mapfielddatafromelemtonode.fld");
  }

  static FieldHandle TetMesh2()
  {
    return loadFieldFromFile(TestResources::rootDir() / "Fields/test_mapfielddatafromnodetoelem.fld");
  }

  static FieldHandle CreateTriSurfScalarOnNode()
  {
    return loadFieldFromFile(TestResources::rootDir() / "Fields/tri_surf/data_defined_on_node/scalar/tri_scalar_on_node.fld");
  }
  static FieldHandle CreateTriSurfVectorOnNode()
  {
    return loadFieldFromFile(TestResources::rootDir() / "Fields/tri_surf/data_defined_on_node/vector/tri_vector_on_node.fld");
  }

  static FieldHandle CreateTetMeshVectorOnNode()
  {
    return loadFieldFromFile(TestResources::rootDir() / "Fields/tet_mesh/data_defined_on_node/vector/tet_vector_on_node.fld");
  }
  static FieldHandle CreateTetMeshScalarOnNode()
  {
    return loadFieldFromFile(TestResources::rootDir() / "Fields/tet_mesh/data_defined_on_node/scalar/tet_scalar_on_node.fld");
  }
  static FieldHandle CreateTetMeshScalarOnElem()
  {
    return loadFieldFromFile(TestResources::rootDir() / "Fields/tet_mesh/data_defined_on_elem/scalar/tet_scalar_on_elem.fld");
  }
  static FieldHandle CreateTetMeshTensorOnNode()
  {
    return loadFieldFromFile(TestResources::rootDir() / "Fields/tet_mesh/data_defined_on_node/tensor/tet_tensor_on_node.fld");
  }

  static FieldHandle CreatePointCloudScalar()
  {
    return loadFieldFromFile(TestResources::rootDir() / "Fields/point_cloud/scalar/pts_scalar.fld");
  }

  static FieldHandle CreateCurveMeshElem()
  {
    return loadFieldFromFile(TestResources::rootDir() / "Fields/test_curve_elem.fld");
  }

  static FieldHandle CreateImageNode()
  {
    return loadFieldFromFile(TestResources::rootDir() / "Fields/test_image_node.fld");
  }

  //static FieldHandle CreatePointCloudScalar()
  //{
  //  return loadFieldFromFile(TestResources::rootDir() / "Fields/point_cloud/scalar/pts_scalar.fld");
  //}

  static std::vector<FieldHandle> fileExamples()
  {
    return{ TetMesh1(), TetMesh2(), CreateTriSurfScalarOnNode(), CreateTriSurfVectorOnNode(), CreateTetMeshVectorOnNode(),
      CreateTetMeshScalarOnElem(), CreateTetMeshScalarOnNode(), CreateTetMeshTensorOnNode(), CreatePointCloudScalar(),
      CreateCurveMeshElem(), CreateImageNode()
    };
  }
};

TEST_F(FieldConversionTests, RoundTripLatVolUsingJustMatlabConversion)
{
  auto expected = CreateEmptyLatVol(2,2,2);
  FieldInformation expectedInfo(expected);
  auto actual = roundTripThroughMatlabConverter(expected);

  ASSERT_TRUE(actual != nullptr);
  auto actualField = boost::dynamic_pointer_cast<Field>(actual);
  ASSERT_TRUE(actualField != nullptr);

  FieldInformation info(actualField);
  ASSERT_EQ(expectedInfo, info);
  EXPECT_TRUE(info.is_latvolmesh());
  EXPECT_TRUE(info.is_double());
  EXPECT_TRUE(info.is_scalar());
  EXPECT_TRUE(info.is_linear());
  EXPECT_EQ("LatVolMesh<HexTrilinearLgn<Point>>", info.get_mesh_type_id());
  EXPECT_EQ("LatVolMesh", info.get_mesh_type());
  EXPECT_EQ("GenericField<LatVolMesh<HexTrilinearLgn<Point>>,HexTrilinearLgn<double>,FData3d<double,LatVolMesh<HexTrilinearLgn<Point>>>>", info.get_field_type_id());
  auto expectedTransform = expected->vmesh()->get_transform();
  auto actualTransform = actualField->vmesh()->get_transform();
  ASSERT_EQ(expectedTransform, actualTransform);
}

TEST_F(FieldConversionTests, RoundTripTetVolUsingJustMatlabConversion)
{
  auto expected = TetMesh1();
  FieldInformation expectedInfo(expected);
  auto actual = roundTripThroughMatlabConverter(expected);

  ASSERT_TRUE(actual != nullptr);
  auto actualField = boost::dynamic_pointer_cast<Field>(actual);
  ASSERT_TRUE(actualField != nullptr);

  FieldInformation info(actualField);
  ASSERT_EQ(expectedInfo, info);
  EXPECT_TRUE(info.is_tetvolmesh());
  EXPECT_TRUE(info.is_double());
  EXPECT_TRUE(info.is_scalar());
  EXPECT_TRUE(info.is_constantdata());
  EXPECT_EQ("TetVolMesh<TetLinearLgn<Point>>", info.get_mesh_type_id());
  EXPECT_EQ("TetVolMesh", info.get_mesh_type());
  EXPECT_EQ("GenericField<TetVolMesh<TetLinearLgn<Point>>,ConstantBasis<double>,vector<double>>", info.get_field_type_id());
}

TEST_F(FieldConversionTests, RoundTripTriSurfUsingJustMatlabConversion)
{
  auto expected = CreateTriSurfScalarOnNode();
  FieldInformation expectedInfo(expected);
  auto actual = roundTripThroughMatlabConverter(expected);

  ASSERT_TRUE(actual != nullptr);
  auto actualField = boost::dynamic_pointer_cast<Field>(actual);
  ASSERT_TRUE(actualField != nullptr);

  FieldInformation info(actualField);
  ASSERT_EQ(expectedInfo, info);
  EXPECT_TRUE(info.is_trisurf());
  EXPECT_TRUE(info.is_double());
  EXPECT_TRUE(info.is_scalar());
  EXPECT_TRUE(info.is_linear());
  EXPECT_EQ("TriSurfMesh<TriLinearLgn<Point>>", info.get_mesh_type_id());
  EXPECT_EQ("TriSurfMesh", info.get_mesh_type());
  EXPECT_EQ("GenericField<TriSurfMesh<TriLinearLgn<Point>>,TriLinearLgn<double>,vector<double>>", info.get_field_type_id());
}

TEST_F(FieldConversionTests, LoopThroughFieldFilesMatlabOnly)
{
  for (const auto& field : fileExamples())
  {
    auto expected = field;
    FieldInformation expectedInfo(expected);
    auto actual = roundTripThroughMatlabConverter(expected);

    ASSERT_TRUE(actual != nullptr);
    auto actualField = boost::dynamic_pointer_cast<Field>(actual);
    ASSERT_TRUE(actualField != nullptr);

    FieldInformation info(actualField);
    ASSERT_EQ(expectedInfo, info);
  }
}

TEST_F(FieldConversionTests, LoopThroughFieldFiles)
{
  for (const auto& field : fileExamples())
  {
    auto expected = field;
    FieldInformation expectedInfo(expected);
    // std::cout << "Converting " << expectedInfo.get_field_type_id() << " to python." << std::endl;
    auto pyField = convertFieldToPython(expected);
    FieldExtractor converter(pyField);

    ASSERT_TRUE(converter.check());

    // std::cout << "Converting " << expectedInfo.get_field_type_id() << " from python." << std::endl;
    auto actual = converter();
    ASSERT_TRUE(actual != nullptr);
    auto actualField = boost::dynamic_pointer_cast<Field>(actual);
    ASSERT_TRUE(actualField != nullptr);

    FieldInformation info(actualField);
    ASSERT_EQ(expectedInfo, info);

    ASSERT_TRUE(compareNodes(expected, actualField));

    std::cout << "Done testing " << expectedInfo.get_field_type_id() << "." << std::endl;
  }
}

TEST_F(FieldConversionTests, RoundTripLatVol)
{
  auto expected = CreateEmptyLatVol();
  auto pyField = convertFieldToPython(expected);
  EXPECT_EQ(9, len(pyField.items()));

  FieldExtractor converter(pyField);

  ASSERT_TRUE(converter.check());

  auto actual = converter();
  ASSERT_TRUE(actual != nullptr);
  auto actualField = boost::dynamic_pointer_cast<Field>(actual);
  ASSERT_TRUE(actualField != nullptr);

  FieldInformation info(actualField);
  EXPECT_TRUE(info.is_latvolmesh());
  EXPECT_TRUE(info.is_double());
  EXPECT_TRUE(info.is_scalar());
  EXPECT_TRUE(info.is_linear());
  EXPECT_EQ("LatVolMesh<HexTrilinearLgn<Point>>", info.get_mesh_type_id());
  EXPECT_EQ("LatVolMesh", info.get_mesh_type());
  EXPECT_EQ("GenericField<LatVolMesh<HexTrilinearLgn<Point>>,HexTrilinearLgn<double>,FData3d<double,LatVolMesh<HexTrilinearLgn<Point>>>>", info.get_field_type_id());
}

TEST_F(FieldConversionTests, RoundTripTriSurf)
{
  auto expected = CreateTriSurfScalarOnNode();
  auto pyField = convertFieldToPython(expected);
  EXPECT_EQ(10, len(pyField.items()));

  FieldExtractor converter(pyField);

  ASSERT_TRUE(converter.check());

  auto actual = converter();
  ASSERT_TRUE(actual != nullptr);
  auto actualField = boost::dynamic_pointer_cast<Field>(actual);
  ASSERT_TRUE(actualField != nullptr);

  FieldInformation info(actualField);
  EXPECT_TRUE(info.is_trisurf());
  EXPECT_TRUE(info.is_double());
  EXPECT_TRUE(info.is_scalar());
  EXPECT_TRUE(info.is_linear());
  EXPECT_EQ("TriSurfMesh<TriLinearLgn<Point>>", info.get_mesh_type_id());
  EXPECT_EQ("TriSurfMesh", info.get_mesh_type());
  EXPECT_EQ("GenericField<TriSurfMesh<TriLinearLgn<Point>>,TriLinearLgn<double>,vector<double>>", info.get_field_type_id());
}

TEST_F(FieldConversionTests, RoundTripTetVolNode)
{
  auto expected = CreateTetMeshScalarOnNode();
  auto pyField = convertFieldToPython(expected);
  EXPECT_EQ(10, len(pyField.items()));

  FieldExtractor converter(pyField);

  ASSERT_TRUE(converter.check());

  auto actual = converter();
  ASSERT_TRUE(actual != nullptr);
  auto actualField = boost::dynamic_pointer_cast<Field>(actual);
  ASSERT_TRUE(actualField != nullptr);

  FieldInformation info(actualField);
  EXPECT_TRUE(info.is_tetvolmesh());
  EXPECT_TRUE(info.is_double());
  EXPECT_TRUE(info.is_scalar());
  EXPECT_TRUE(info.is_linear());
  EXPECT_EQ("TetVolMesh<TetLinearLgn<Point>>", info.get_mesh_type_id());
  EXPECT_EQ("TetVolMesh", info.get_mesh_type());
  EXPECT_EQ("GenericField<TetVolMesh<TetLinearLgn<Point>>,TetLinearLgn<double>,vector<double>>", info.get_field_type_id());
}

TEST_F(FieldConversionTests, RoundTripTetVolCell)
{
  auto expected = CreateTetMeshScalarOnElem();
  auto pyField = convertFieldToPython(expected);
  EXPECT_EQ(10, len(pyField.items()));

  FieldExtractor converter(pyField);

  ASSERT_TRUE(converter.check());

  auto actual = converter();
  ASSERT_TRUE(actual != nullptr);
  auto actualField = boost::dynamic_pointer_cast<Field>(actual);
  ASSERT_TRUE(actualField != nullptr);

  FieldInformation info(actualField);
  EXPECT_TRUE(info.is_tetvolmesh());
  EXPECT_TRUE(info.is_double());
  EXPECT_TRUE(info.is_scalar());
  EXPECT_TRUE(info.is_constantdata());
  EXPECT_EQ("TetVolMesh<TetLinearLgn<Point>>", info.get_mesh_type_id());
  EXPECT_EQ("TetVolMesh", info.get_mesh_type());
  EXPECT_EQ("GenericField<TetVolMesh<TetLinearLgn<Point>>,ConstantBasis<double>,vector<double>>", info.get_field_type_id());
}

TEST_F(FieldConversionTests, RejectsEmptyDictionary)
{
  boost::python::dict emptyDict;
  FieldExtractor converter(emptyDict);

  ASSERT_FALSE(converter.check());
}

TEST_F(FieldConversionTests, RejectsIncompatibleDictionary)
{
  boost::python::dict dict;
  dict.setdefault(2, 5);
  ASSERT_EQ(1, len(dict));
  FieldExtractor converter(dict);

  ASSERT_FALSE(converter.check());
}
<commit_msg>Test for brett's failing mesh<commit_after>/*
   For more information, please see: http://software.sci.utah.edu

   The MIT License

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

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

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

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

#include <Python.h>
#include <boost/python.hpp>

#include <gtest/gtest.h>
#include <Testing/ModuleTestBase/ModuleTestBase.h>
#include <Core/Python/PythonDatatypeConverter.h>
#include <Core/Datatypes/Legacy/Field/FieldInformation.h>
#include <Core/Matlab/matlabconverter.h>
#include <Core/Datatypes/Legacy/Field/VMesh.h>
#include <Testing/Utils/MatrixTestUtilities.h>
#include <Testing/Utils/SCIRunUnitTests.h>
#include <Testing/Utils/SCIRunFieldSamples.h>
#ifdef WIN32
#ifndef DEBUG
#include <Core/Python/PythonInterpreter.h>
#endif
#endif

using namespace SCIRun;
using namespace SCIRun::Core;
using namespace Core::Python;
using namespace Testing;
using namespace TestUtils;

class FieldConversionTests : public testing::Test
{
protected:
  virtual void SetUp() override
  {
  #ifdef WIN32
  #ifndef DEBUG
    PythonInterpreter::Instance().initialize(false, "Core_Python_Tests", boost::filesystem::current_path().string());
    PythonInterpreter::Instance().run_string("import SCIRunPythonAPI; from SCIRunPythonAPI import *");
  #endif
  #else
    Py_Initialize();
  #endif
  }

  static FieldHandle roundTripThroughMatlabConverter(FieldHandle field)
  {
    MatlabIO::matlabarray ma;
    {
      MatlabIO::matlabconverter mc(nullptr);
      mc.converttostructmatrix();
      mc.sciFieldTOmlArray(field, ma);
    }

    FieldHandle actual;
    {
      MatlabIO::matlabconverter mc(nullptr);
      mc.mlArrayTOsciField(ma, actual);
    }
    return actual;
  }

  static FieldHandle TetMesh1()
  {
    return loadFieldFromFile(TestResources::rootDir() / "Fields/test_mapfielddatafromelemtonode.fld");
  }

  static FieldHandle TetMesh2()
  {
    return loadFieldFromFile(TestResources::rootDir() / "Fields/test_mapfielddatafromnodetoelem.fld");
  }

  static FieldHandle CreateTriSurfScalarOnNode()
  {
    return loadFieldFromFile(TestResources::rootDir() / "Fields/tri_surf/data_defined_on_node/scalar/tri_scalar_on_node.fld");
  }
  static FieldHandle CreateTriSurfVectorOnNode()
  {
    return loadFieldFromFile(TestResources::rootDir() / "Fields/tri_surf/data_defined_on_node/vector/tri_vector_on_node.fld");
  }

  static FieldHandle CreateTetMeshVectorOnNode()
  {
    return loadFieldFromFile(TestResources::rootDir() / "Fields/tet_mesh/data_defined_on_node/vector/tet_vector_on_node.fld");
  }
  static FieldHandle CreateTetMeshScalarOnNode()
  {
    return loadFieldFromFile(TestResources::rootDir() / "Fields/tet_mesh/data_defined_on_node/scalar/tet_scalar_on_node.fld");
  }
  static FieldHandle CreateTetMeshScalarOnElem()
  {
    return loadFieldFromFile(TestResources::rootDir() / "Fields/tet_mesh/data_defined_on_elem/scalar/tet_scalar_on_elem.fld");
  }
  static FieldHandle CreateTetMeshTensorOnNode()
  {
    return loadFieldFromFile(TestResources::rootDir() / "Fields/tet_mesh/data_defined_on_node/tensor/tet_tensor_on_node.fld");
  }

  static FieldHandle CreatePointCloudScalar()
  {
    return loadFieldFromFile(TestResources::rootDir() / "Fields/point_cloud/scalar/pts_scalar.fld");
  }

  static FieldHandle CreateCurveMeshElem()
  {
    return loadFieldFromFile(TestResources::rootDir() / "Fields/test_curve_elem.fld");
  }

  static FieldHandle CreateImageNode()
  {
    return loadFieldFromFile(TestResources::rootDir() / "Fields/test_image_node.fld");
  }

  static FieldHandle CreateTriSurfFromCVRTI()
  {
    return loadFieldFromFile(TestResources::rootDir() / "Fields/CVRTI_cappedTorso/CappedTorso_192.fld");
  }

  static std::vector<FieldHandle> fileExamples()
  {
    return{ TetMesh1(), TetMesh2(), CreateTriSurfScalarOnNode(), CreateTriSurfVectorOnNode(), CreateTetMeshVectorOnNode(),
      CreateTetMeshScalarOnElem(), CreateTetMeshScalarOnNode(), CreateTetMeshTensorOnNode(), CreatePointCloudScalar(),
      CreateCurveMeshElem(), CreateImageNode()
    };
  }
};

TEST_F(FieldConversionTests, RoundTripLatVolUsingJustMatlabConversion)
{
  auto expected = CreateEmptyLatVol(2,2,2);
  FieldInformation expectedInfo(expected);
  auto actual = roundTripThroughMatlabConverter(expected);

  ASSERT_TRUE(actual != nullptr);
  auto actualField = boost::dynamic_pointer_cast<Field>(actual);
  ASSERT_TRUE(actualField != nullptr);

  FieldInformation info(actualField);
  ASSERT_EQ(expectedInfo, info);
  EXPECT_TRUE(info.is_latvolmesh());
  EXPECT_TRUE(info.is_double());
  EXPECT_TRUE(info.is_scalar());
  EXPECT_TRUE(info.is_linear());
  EXPECT_EQ("LatVolMesh<HexTrilinearLgn<Point>>", info.get_mesh_type_id());
  EXPECT_EQ("LatVolMesh", info.get_mesh_type());
  EXPECT_EQ("GenericField<LatVolMesh<HexTrilinearLgn<Point>>,HexTrilinearLgn<double>,FData3d<double,LatVolMesh<HexTrilinearLgn<Point>>>>", info.get_field_type_id());
  auto expectedTransform = expected->vmesh()->get_transform();
  auto actualTransform = actualField->vmesh()->get_transform();
  ASSERT_EQ(expectedTransform, actualTransform);
}

TEST_F(FieldConversionTests, RoundTripTetVolUsingJustMatlabConversion)
{
  auto expected = TetMesh1();
  FieldInformation expectedInfo(expected);
  auto actual = roundTripThroughMatlabConverter(expected);

  ASSERT_TRUE(actual != nullptr);
  auto actualField = boost::dynamic_pointer_cast<Field>(actual);
  ASSERT_TRUE(actualField != nullptr);

  FieldInformation info(actualField);
  ASSERT_EQ(expectedInfo, info);
  EXPECT_TRUE(info.is_tetvolmesh());
  EXPECT_TRUE(info.is_double());
  EXPECT_TRUE(info.is_scalar());
  EXPECT_TRUE(info.is_constantdata());
  EXPECT_EQ("TetVolMesh<TetLinearLgn<Point>>", info.get_mesh_type_id());
  EXPECT_EQ("TetVolMesh", info.get_mesh_type());
  EXPECT_EQ("GenericField<TetVolMesh<TetLinearLgn<Point>>,ConstantBasis<double>,vector<double>>", info.get_field_type_id());
}

TEST_F(FieldConversionTests, RoundTripTriSurfUsingJustMatlabConversion)
{
  auto expected = CreateTriSurfScalarOnNode();
  FieldInformation expectedInfo(expected);
  auto actual = roundTripThroughMatlabConverter(expected);

  ASSERT_TRUE(actual != nullptr);
  auto actualField = boost::dynamic_pointer_cast<Field>(actual);
  ASSERT_TRUE(actualField != nullptr);

  FieldInformation info(actualField);
  ASSERT_EQ(expectedInfo, info);
  EXPECT_TRUE(info.is_trisurf());
  EXPECT_TRUE(info.is_double());
  EXPECT_TRUE(info.is_scalar());
  EXPECT_TRUE(info.is_linear());
  EXPECT_EQ("TriSurfMesh<TriLinearLgn<Point>>", info.get_mesh_type_id());
  EXPECT_EQ("TriSurfMesh", info.get_mesh_type());
  EXPECT_EQ("GenericField<TriSurfMesh<TriLinearLgn<Point>>,TriLinearLgn<double>,vector<double>>", info.get_field_type_id());
}

TEST_F(FieldConversionTests, LoopThroughFieldFilesMatlabOnly)
{
  for (const auto& field : fileExamples())
  {
    auto expected = field;
    FieldInformation expectedInfo(expected);
    auto actual = roundTripThroughMatlabConverter(expected);

    ASSERT_TRUE(actual != nullptr);
    auto actualField = boost::dynamic_pointer_cast<Field>(actual);
    ASSERT_TRUE(actualField != nullptr);

    FieldInformation info(actualField);
    ASSERT_EQ(expectedInfo, info);
  }
}

TEST_F(FieldConversionTests, LoopThroughFieldFiles)
{
  for (const auto& field : fileExamples())
  {
    auto expected = field;
    FieldInformation expectedInfo(expected);
    // std::cout << "Converting " << expectedInfo.get_field_type_id() << " to python." << std::endl;
    auto pyField = convertFieldToPython(expected);
    FieldExtractor converter(pyField);

    ASSERT_TRUE(converter.check());

    // std::cout << "Converting " << expectedInfo.get_field_type_id() << " from python." << std::endl;
    auto actual = converter();
    ASSERT_TRUE(actual != nullptr);
    auto actualField = boost::dynamic_pointer_cast<Field>(actual);
    ASSERT_TRUE(actualField != nullptr);

    FieldInformation info(actualField);
    ASSERT_EQ(expectedInfo, info);

    ASSERT_TRUE(compareNodes(expected, actualField));

    std::cout << "Done testing " << expectedInfo.get_field_type_id() << "." << std::endl;
  }
}

TEST_F(FieldConversionTests, RoundTripLatVol)
{
  auto expected = CreateEmptyLatVol();
  auto pyField = convertFieldToPython(expected);
  EXPECT_EQ(9, len(pyField.items()));

  FieldExtractor converter(pyField);

  ASSERT_TRUE(converter.check());

  auto actual = converter();
  ASSERT_TRUE(actual != nullptr);
  auto actualField = boost::dynamic_pointer_cast<Field>(actual);
  ASSERT_TRUE(actualField != nullptr);

  FieldInformation info(actualField);
  EXPECT_TRUE(info.is_latvolmesh());
  EXPECT_TRUE(info.is_double());
  EXPECT_TRUE(info.is_scalar());
  EXPECT_TRUE(info.is_linear());
  EXPECT_EQ("LatVolMesh<HexTrilinearLgn<Point>>", info.get_mesh_type_id());
  EXPECT_EQ("LatVolMesh", info.get_mesh_type());
  EXPECT_EQ("GenericField<LatVolMesh<HexTrilinearLgn<Point>>,HexTrilinearLgn<double>,FData3d<double,LatVolMesh<HexTrilinearLgn<Point>>>>", info.get_field_type_id());
}

TEST_F(FieldConversionTests, RoundTripTriSurf)
{
  auto expected = CreateTriSurfScalarOnNode();
  auto pyField = convertFieldToPython(expected);
  EXPECT_EQ(10, len(pyField.items()));

  FieldExtractor converter(pyField);

  ASSERT_TRUE(converter.check());

  auto actual = converter();
  ASSERT_TRUE(actual != nullptr);
  auto actualField = boost::dynamic_pointer_cast<Field>(actual);
  ASSERT_TRUE(actualField != nullptr);

  FieldInformation info(actualField);
  EXPECT_TRUE(info.is_trisurf());
  EXPECT_TRUE(info.is_double());
  EXPECT_TRUE(info.is_scalar());
  EXPECT_TRUE(info.is_linear());
  EXPECT_EQ("TriSurfMesh<TriLinearLgn<Point>>", info.get_mesh_type_id());
  EXPECT_EQ("TriSurfMesh", info.get_mesh_type());
  EXPECT_EQ("GenericField<TriSurfMesh<TriLinearLgn<Point>>,TriLinearLgn<double>,vector<double>>", info.get_field_type_id());
}

TEST_F(FieldConversionTests, RoundTripTetVolNode)
{
  auto expected = CreateTetMeshScalarOnNode();
  auto pyField = convertFieldToPython(expected);
  EXPECT_EQ(10, len(pyField.items()));

  FieldExtractor converter(pyField);

  ASSERT_TRUE(converter.check());

  auto actual = converter();
  ASSERT_TRUE(actual != nullptr);
  auto actualField = boost::dynamic_pointer_cast<Field>(actual);
  ASSERT_TRUE(actualField != nullptr);

  FieldInformation info(actualField);
  EXPECT_TRUE(info.is_tetvolmesh());
  EXPECT_TRUE(info.is_double());
  EXPECT_TRUE(info.is_scalar());
  EXPECT_TRUE(info.is_linear());
  EXPECT_EQ("TetVolMesh<TetLinearLgn<Point>>", info.get_mesh_type_id());
  EXPECT_EQ("TetVolMesh", info.get_mesh_type());
  EXPECT_EQ("GenericField<TetVolMesh<TetLinearLgn<Point>>,TetLinearLgn<double>,vector<double>>", info.get_field_type_id());
}

TEST_F(FieldConversionTests, RoundTripTriSurfCVRTI)
{
  auto expected = CreateTriSurfFromCVRTI();
  auto pyField = convertFieldToPython(expected);
  EXPECT_EQ(10, len(pyField.items()));

  FieldExtractor converter(pyField);

  ASSERT_TRUE(converter.check());

  auto actual = converter();
  ASSERT_TRUE(actual != nullptr);
  auto actualField = boost::dynamic_pointer_cast<Field>(actual);
  ASSERT_TRUE(actualField != nullptr);

  FieldInformation info(actualField);
  EXPECT_TRUE(info.is_trisurf());
  EXPECT_TRUE(info.is_double());
  EXPECT_TRUE(info.is_scalar());
  EXPECT_TRUE(info.is_linear());
  EXPECT_EQ("TriSurfMesh<TriLinearLgn<Point>>", info.get_mesh_type_id());
  EXPECT_EQ("TriSurfMesh", info.get_mesh_type());
  EXPECT_EQ("GenericField<TriSurfMesh<TriLinearLgn<Point>>,TriLinearLgn<double>,vector<double>>", info.get_field_type_id());
}

TEST_F(FieldConversionTests, RoundTripTetVolCell)
{
  auto expected = CreateTetMeshScalarOnElem();
  auto pyField = convertFieldToPython(expected);
  EXPECT_EQ(10, len(pyField.items()));

  FieldExtractor converter(pyField);

  ASSERT_TRUE(converter.check());

  auto actual = converter();
  ASSERT_TRUE(actual != nullptr);
  auto actualField = boost::dynamic_pointer_cast<Field>(actual);
  ASSERT_TRUE(actualField != nullptr);

  FieldInformation info(actualField);
  EXPECT_TRUE(info.is_tetvolmesh());
  EXPECT_TRUE(info.is_double());
  EXPECT_TRUE(info.is_scalar());
  EXPECT_TRUE(info.is_constantdata());
  EXPECT_EQ("TetVolMesh<TetLinearLgn<Point>>", info.get_mesh_type_id());
  EXPECT_EQ("TetVolMesh", info.get_mesh_type());
  EXPECT_EQ("GenericField<TetVolMesh<TetLinearLgn<Point>>,ConstantBasis<double>,vector<double>>", info.get_field_type_id());
}

TEST_F(FieldConversionTests, RejectsEmptyDictionary)
{
  boost::python::dict emptyDict;
  FieldExtractor converter(emptyDict);

  ASSERT_FALSE(converter.check());
}

TEST_F(FieldConversionTests, RejectsIncompatibleDictionary)
{
  boost::python::dict dict;
  dict.setdefault(2, 5);
  ASSERT_EQ(1, len(dict));
  FieldExtractor converter(dict);

  ASSERT_FALSE(converter.check());
}
<|endoftext|>