<commit_before>
#include <time.h>
#include <stdio.h>
#include <sys/ioctl.h>

#include "yacasprivate.h"
#include "unixcommandline.h"

void CUnixCommandLine::NewLine()
{
    _cursor_line = 0;
    _last_line = 0;

    printf("\n");

    fflush(stdout);
}

void CUnixCommandLine::Pause()
{
    clock_t i=clock()+CLOCKS_PER_SEC/4;
    while (clock()<i);
}

void CUnixCommandLine::ShowLine(
    const LispChar* prompt,
    LispInt promptlen,
    LispInt cursor)
{
    struct winsize w;
    ioctl(0, TIOCGWINSZ, &w);

    const LispInt l = (cursor + promptlen) / w.ws_col;
    const LispInt c = (cursor + promptlen) % w.ws_col;

    if (_cursor_line)
        printf("\x1b[%dF", _cursor_line);

    if (iFullLineDirty) {
        if (_last_line)
            printf("\x1b[%dB", _last_line);

        for (LispInt i = 0; i < _last_line; ++i)
            printf("\r\x1b[K\x1b[F");

        printf("\r\x1b[K\x1b[K%s%s", prompt, &iSubLine[0]);

        if ((promptlen + strlen(&iSubLine[0])) % w.ws_col == 0)
            printf("\x1b[E");

        _last_line = (promptlen + strlen(&iSubLine[0])) / w.ws_col;
        if (_last_line)
            printf("\x1b[%dF", _last_line);
    }

    if (l)
        printf("\r\x1b[%dB", l);

    printf("\r\x1b[%dG", c + 1);

    fflush(stdout);

    _cursor_line = l;

    iFullLineDirty = 0;
}

CUnixCommandLine::CUnixCommandLine():
    _cursor_line(0),
    _last_line(0),
    iMaxLines(1024)
{
    /* set termio so we can do our own input processing */
    tcgetattr(0, &orig_termio);
    rl_termio = orig_termio;
    rl_termio.c_iflag &= ~(BRKINT|PARMRK|INPCK/*|IUCLC*/|IXON|IXOFF);
    rl_termio.c_iflag |=  (IGNBRK|IGNPAR);
    /* rl_termio.c_oflag &= ~(ONOCR); Costas Sphocleous Irvine,CA */
    rl_termio.c_lflag &= ~(ICANON|ECHO|ECHOE|ECHOK|ECHONL|NOFLSH);
    rl_termio.c_lflag |=  (ISIG);
    rl_termio.c_cc[VMIN] = 1;
    rl_termio.c_cc[VTIME] = 0;
    term_chars[VERASE]   = orig_termio.c_cc[VERASE];
    term_chars[VEOF]     = orig_termio.c_cc[VEOF];
    term_chars[VKILL]    = orig_termio.c_cc[VKILL];
    term_chars[VWERASE]  = orig_termio.c_cc[VWERASE];
    term_chars[VREPRINT] = orig_termio.c_cc[VREPRINT];
    term_chars[VSUSP]    = orig_termio.c_cc[VSUSP];
    /* disable suspending process on ^Z */
    rl_termio.c_cc[VSUSP] = 0;
    tcsetattr(0, TCSADRAIN, &rl_termio);

    char fname[256];
#ifdef HAVE_VSNPRINTF
    snprintf(fname,256,"%s/.yacas_history",getenv("HOME"));
#else
    sprintf(fname,"%s/.yacas_history",getenv("HOME"));
#endif
    FILE*f=fopen(fname,"r");
    if (f)
    {
        if(f)
        {
#define BufSz 256
            char buff[BufSz];
            while(fgets(buff,BufSz-2,f))
            {
                int i;
                for(i=0;buff[i] && buff[i] != '\n';++i)
                    ;
                buff[i++] = '\0';
                LispString * ptr = NEW LispString(buff);
                iHistoryList.Append(ptr);

            }
            fclose(f);
        }
    }
    iMaxLines = 1024;
}

CUnixCommandLine::~CUnixCommandLine()
{
    tcsetattr(0, TCSADRAIN, &orig_termio);
    char fname[256];
#ifdef HAVE_VSNPRINTF
    snprintf(fname,256,"%s/.yacas_history",getenv("HOME"));
#else
    sprintf(fname,"%s/.yacas_history",getenv("HOME"));
#endif

    FILE*f=fopen(fname,"w");
    if (f)
    {
        int i;
        int from=0;
        if (iMaxLines>=0)
        {
            if (iHistoryList.NrLines()>iMaxLines)
            {
                from = iHistoryList.NrLines()-iMaxLines;
            }
        }
        for (i=from;i<iHistoryList.NrLines();i++)
        {
          LispString * ptr = iHistoryList.GetLine(i);

            fprintf(f,"%s\n",ptr->c_str());
        }
        fclose(f);
    }
}

void CUnixCommandLine::MaxHistoryLinesSaved(LispInt aNrLines)
{
    iMaxLines = aNrLines;
}

LispInt CUnixCommandLine::GetKey()
{
    LispInt c = getc(stdin);

    if (feof(stdin))
        exit(0);

    if (c == term_chars[VERASE]) /* Backspace */
    {
        c = eBackSpace;
    }
    else if (c == term_chars[VEOF]) /* delete */
    {
        c = eDelete;
    }
    else
    {
        switch (c)
        {
        case 9: //  9   tab
            c = eTab;
            break;
        case 10:        /* Enter */
            c = eEnter;
            break;
        case 001:    /* ^A  (unix home) */
            c = eHome;
            break;
        case 005:    /* ^E  (unix end) */
            c = eEnd;
            break;
        case 004:    /* ^D  (unix delete) */
        case 127:
            c = eDelete;
            break;
        case  8:              /* ^H  (unix backspace) */
            c = eBackSpace;
            break;
        case 033:
            {
                c = getc(stdin); /* check for CSI */

                switch (c)
                {
                case 27:
                    c=eEscape;
                    break;
                case '[':
                    {
                        c = getc(stdin); /* get command character */
                        switch (c)
                        {
                        case 'D': /* left arrow key */
                            c = eLeft;
                            break;
                        case 'C': /* right arrow key */
                            c = eRight;
                            break;
                        case 'A': /* up arrow key */
                            c = eUp;
                            break;
                        case 'B': /* down arrow key */
                            c = eDown;
                            break;
                        case 'H': /* home */
                            c = eHome;
                            break;
                        case 'F': /* end */
                            c = eEnd;
                            break;
                        }
                    }
                    break;
                }
            }
            break;
        }
    }
    return c;
}

<commit_msg>corrected behaviour of the unix console when scrolling is involved<commit_after>
#include <time.h>
#include <stdio.h>
#include <sys/ioctl.h>

#include "yacasprivate.h"
#include "unixcommandline.h"

void CUnixCommandLine::NewLine()
{
    _cursor_line = 0;
    _last_line = 0;

    printf("\n");

    fflush(stdout);
}

void CUnixCommandLine::Pause()
{
    clock_t i=clock()+CLOCKS_PER_SEC/4;
    while (clock()<i);
}

void CUnixCommandLine::ShowLine(
    const LispChar* prompt,
    LispInt promptlen,
    LispInt cursor)
{
    struct winsize w;
    ioctl(0, TIOCGWINSZ, &w);

    const LispInt l = (cursor + promptlen) / w.ws_col;
    const LispInt c = (cursor + promptlen) % w.ws_col;

    if (_cursor_line)
        printf("\x1b[%dF", _cursor_line);

    if (iFullLineDirty) {
        if (_last_line)
            printf("\x1b[%dB", _last_line);

        for (LispInt i = 0; i < _last_line; ++i)
            printf("\r\x1b[K\x1b[F");

        printf("\r\x1b[K\x1b[K%s%s", prompt, &iSubLine[0]);

        if ((promptlen + strlen(&iSubLine[0])) % w.ws_col == 0)
            printf("\n");

        _last_line = (promptlen + strlen(&iSubLine[0])) / w.ws_col;
        if (_last_line)
            printf("\x1b[%dF", _last_line);
    }

    if (l)
        printf("\r\x1b[%dB", l);

    printf("\r\x1b[%dG", c + 1);

    fflush(stdout);

    _cursor_line = l;

    iFullLineDirty = 0;
}

CUnixCommandLine::CUnixCommandLine():
    _cursor_line(0),
    _last_line(0),
    iMaxLines(1024)
{
    /* set termio so we can do our own input processing */
    tcgetattr(0, &orig_termio);
    rl_termio = orig_termio;
    rl_termio.c_iflag &= ~(BRKINT|PARMRK|INPCK/*|IUCLC*/|IXON|IXOFF);
    rl_termio.c_iflag |=  (IGNBRK|IGNPAR);
    /* rl_termio.c_oflag &= ~(ONOCR); Costas Sphocleous Irvine,CA */
    rl_termio.c_lflag &= ~(ICANON|ECHO|ECHOE|ECHOK|ECHONL|NOFLSH);
    rl_termio.c_lflag |=  (ISIG);
    rl_termio.c_cc[VMIN] = 1;
    rl_termio.c_cc[VTIME] = 0;
    term_chars[VERASE]   = orig_termio.c_cc[VERASE];
    term_chars[VEOF]     = orig_termio.c_cc[VEOF];
    term_chars[VKILL]    = orig_termio.c_cc[VKILL];
    term_chars[VWERASE]  = orig_termio.c_cc[VWERASE];
    term_chars[VREPRINT] = orig_termio.c_cc[VREPRINT];
    term_chars[VSUSP]    = orig_termio.c_cc[VSUSP];
    /* disable suspending process on ^Z */
    rl_termio.c_cc[VSUSP] = 0;
    tcsetattr(0, TCSADRAIN, &rl_termio);

    char fname[256];
#ifdef HAVE_VSNPRINTF
    snprintf(fname,256,"%s/.yacas_history",getenv("HOME"));
#else
    sprintf(fname,"%s/.yacas_history",getenv("HOME"));
#endif
    FILE*f=fopen(fname,"r");
    if (f)
    {
        if(f)
        {
#define BufSz 256
            char buff[BufSz];
            while(fgets(buff,BufSz-2,f))
            {
                int i;
                for(i=0;buff[i] && buff[i] != '\n';++i)
                    ;
                buff[i++] = '\0';
                LispString * ptr = NEW LispString(buff);
                iHistoryList.Append(ptr);

            }
            fclose(f);
        }
    }
    iMaxLines = 1024;
}

CUnixCommandLine::~CUnixCommandLine()
{
    tcsetattr(0, TCSADRAIN, &orig_termio);
    char fname[256];
#ifdef HAVE_VSNPRINTF
    snprintf(fname,256,"%s/.yacas_history",getenv("HOME"));
#else
    sprintf(fname,"%s/.yacas_history",getenv("HOME"));
#endif

    FILE*f=fopen(fname,"w");
    if (f)
    {
        int i;
        int from=0;
        if (iMaxLines>=0)
        {
            if (iHistoryList.NrLines()>iMaxLines)
            {
                from = iHistoryList.NrLines()-iMaxLines;
            }
        }
        for (i=from;i<iHistoryList.NrLines();i++)
        {
          LispString * ptr = iHistoryList.GetLine(i);

            fprintf(f,"%s\n",ptr->c_str());
        }
        fclose(f);
    }
}

void CUnixCommandLine::MaxHistoryLinesSaved(LispInt aNrLines)
{
    iMaxLines = aNrLines;
}

LispInt CUnixCommandLine::GetKey()
{
    LispInt c = getc(stdin);

    if (feof(stdin))
        exit(0);

    if (c == term_chars[VERASE]) /* Backspace */
    {
        c = eBackSpace;
    }
    else if (c == term_chars[VEOF]) /* delete */
    {
        c = eDelete;
    }
    else
    {
        switch (c)
        {
        case 9: //  9   tab
            c = eTab;
            break;
        case 10:        /* Enter */
            c = eEnter;
            break;
        case 001:    /* ^A  (unix home) */
            c = eHome;
            break;
        case 005:    /* ^E  (unix end) */
            c = eEnd;
            break;
        case 004:    /* ^D  (unix delete) */
        case 127:
            c = eDelete;
            break;
        case  8:              /* ^H  (unix backspace) */
            c = eBackSpace;
            break;
        case 033:
            {
                c = getc(stdin); /* check for CSI */

                switch (c)
                {
                case 27:
                    c=eEscape;
                    break;
                case '[':
                    {
                        c = getc(stdin); /* get command character */
                        switch (c)
                        {
                        case 'D': /* left arrow key */
                            c = eLeft;
                            break;
                        case 'C': /* right arrow key */
                            c = eRight;
                            break;
                        case 'A': /* up arrow key */
                            c = eUp;
                            break;
                        case 'B': /* down arrow key */
                            c = eDown;
                            break;
                        case 'H': /* home */
                            c = eHome;
                            break;
                        case 'F': /* end */
                            c = eEnd;
                            break;
                        }
                    }
                    break;
                }
            }
            break;
        }
    }
    return c;
}

<|endoftext|>


<commit_before>// Copyright (c) 2013, German Neuroinformatics Node (G-Node)
//
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted under the terms of the BSD License. See
// LICENSE file in the root of the Project.

#include <string>
#include <cstdlib>
#include <cmath>
#include <algorithm>

#include <boost/optional.hpp>

#include <nix/util/util.hpp>
#include <nix/util/dataAccess.hpp>

using namespace std;

namespace nix {
namespace util {

int positionToIndex(double position, const string &unit, const Dimension &dimension) {
    if (dimension.dimensionType() == nix::DimensionType::Sample) {
        SampledDimension dim;
        dim = dimension;
        return positionToIndex(position, unit, dim);
    } else if (dimension.dimensionType() == nix::DimensionType::Set) {
        SetDimension dim;
        dim = dimension;
        return positionToIndex(position, unit, dim);
    } else {
        RangeDimension dim;
        dim = dimension;
        return positionToIndex(position, unit, dim);
    }
}

size_t positionToIndex(double position, const string &unit, const SampledDimension &dimension) {
    size_t index;
    boost::optional<string> dim_unit = dimension.unit();
    double scaling = 1.0;
    if (!dim_unit && unit != "none") {
        throw nix::IncompatibleDimensions("Units of position and SampledDimension must both be given!", "nix::util::positionToIndex");
    }
    if (dim_unit && unit != "none") {
        try {
            scaling = util::getSIScaling(unit, *dim_unit);
        } catch (...) {
            throw nix::IncompatibleDimensions("Cannot apply a position with unit to a SetDimension", "nix::util::positionToIndex");
        }
    }
    index = dimension.indexOf(position * scaling);
    return index;
}

size_t positionToIndex(double position, const string &unit, const SetDimension &dimension) {
    size_t index;
    index = static_cast<size_t>(round(position));
    if (unit.length() > 0 && unit != "none") {
        throw nix::IncompatibleDimensions("Cannot apply a position with unit to a SetDimension", "nix::util::positionToIndex");
    }

    if (dimension.labels().size() > 0 && index > dimension.labels().size()) {
        throw nix::OutOfBounds("Position is out of bounds in setDimension.", static_cast<int>(position));
    }
    return index;
}

size_t positionToIndex(double position, const string &unit, const RangeDimension &dimension) {
    size_t index;
    boost::optional<string> dim_unit = dimension.unit();
    double scaling = 1.0;

    if (dim_unit && unit != "none") {
        try {
            scaling = util::getSIScaling(unit, *dim_unit);
        } catch (...) {
            throw nix::IncompatibleDimensions("Provided units are not scalable!", "nix::util::positionToIndex");
        }
    }
    vector<double> ticks = dimension.ticks();
    if (position*scaling < *ticks.begin()) {
        return 0;
    } else if (position*scaling > *prev(ticks.end())) {
        return prev(ticks.end()) - ticks.begin();
    }
    vector<double>::iterator low = std::lower_bound (ticks.begin(), ticks.end(), position * scaling);
    if (*low == position) {
        return low - ticks.begin();
    }
    if (low != ticks.begin() && *low != position * scaling) {
        double diff_low, diff_before;
        diff_low = fabs(*low - position);
        diff_before = fabs(*(std::prev(low)) - position * scaling);
        if (diff_low < diff_before) {
            index = low - ticks.begin();
        } else {
            index = low - ticks.begin() - 1;
        }
        return index;
    } else {
        return low - ticks.begin();
    }
}

void getOffsetAndCount(const Tag &tag, const DataArray &array, NDSize &offset, NDSize &count) {
    vector<double> position = tag.position();
    vector<double> extent = tag.extent();
    vector<string> units = tag.units();
    NDSize temp_offset(position.size());
    NDSize temp_count(position.size(), 1);

    if (array.dimensionCount() != position.size() || (extent.size() > 0 && extent.size() != array.dimensionCount())) {
        throw std::runtime_error("Dimensionality of position or extent vector does not match dimensionality of data!");
    }
    for (size_t i = 0; i < position.size(); ++i) {
        Dimension dim = array.getDimension(i+1);
        temp_offset[i] = positionToIndex(position[i], i >= units.size() ? "none" : units[i], dim);
        if (i < extent.size()) {
            size_t c = positionToIndex(position[i] + extent[i], i >= units.size() ? "none" : units[i], dim) - temp_offset[i];
            temp_count[i] = (c > 1) ? c : 1;
        }
    }
    offset = temp_offset;
    count = temp_count;
}

void getOffsetAndCount(const MultiTag &tag, const DataArray &array, size_t index, NDSize &offsets, NDSize &counts) {
    DataArray positions = tag.positions();
    DataArray extents = tag.extents();
    NDSize position_size, extent_size;
    size_t dimension_count = array.dimensionCount();

    if (positions) {
        position_size = positions.dataExtent();
    }

    if (extents) {
        extent_size = extents.dataExtent();
    }

    if (!positions || index >= position_size[0]) {
        throw nix::OutOfBounds("Index out of bounds of positions!", 0);
    }

    if (extents && index >= extent_size[0]) {
        throw nix::OutOfBounds("Index out of bounds of positions or extents!", 0);
    }

    if (position_size.size() == 1 && dimension_count != 1) {
        throw nix::IncompatibleDimensions("Number of dimensions in positions does not match dimensionality of data",
                                          "util::getOffsetAndCount");
    }

    if (position_size.size() > 1 && position_size[1] > dimension_count) {
        throw nix::IncompatibleDimensions("Number of dimensions in positions does not match dimensionality of data",
                                          "util::getOffsetAndCount");
    }

    if (extents && extent_size.size() > 1 && extent_size[1] > dimension_count) {
        throw nix::IncompatibleDimensions("Number of dimensions in extents does not match dimensionality of data",
                                          "util::getOffsetAndCount");
    }

    NDSize temp_offset = NDSize{static_cast<NDSize::value_type>(index), static_cast<NDSize::value_type>(0)};
    NDSize temp_count{static_cast<NDSize::value_type>(1), static_cast<NDSize::value_type>(dimension_count)};
    NDArray offset(positions.dataType(), temp_count);
    positions.getData(offset, temp_count, temp_offset);

    NDSize data_offset(dimension_count, static_cast<size_t>(0));
    NDSize data_count(dimension_count, static_cast<size_t>(1));
    vector<string> units = tag.units();
    double pos;
    for (size_t i = 0; i < offset.num_elements(); ++i) {
        Dimension dimension = array.getDimension(i+1);
        string unit = "none";
        if (i <= units.size() && units.size() > 0) {
            unit = units[i];
        }
        if (offset.dtype() == nix::DataType::Double) {
            pos = offset.get<double>(i);
        } else if (offset.dtype() == nix::DataType::Int64) {
            pos = static_cast<double>(offset.get<int>(i));
        } else {
            throw std::runtime_error("Unexpected DataType for the position, expect double or integer!");
        }
        data_offset[i] = positionToIndex(pos, unit, dimension);
    }
    if (extents) {
        NDArray extent(extents.dataType(), temp_count);
        extents.getData(extent, temp_count, temp_offset);
        for (size_t i = 0; i < extent.num_elements(); ++i) {
            Dimension dimension = array.getDimension(i+1);
            string unit = "none";
            if (i <= units.size() && units.size() > 0) {
                unit = units[i];
            }
            double endPos;
            if (extent.dtype() == nix::DataType::Double) {
                endPos = pos + extent.get<double>(i);
            } else if (extent.dtype() == nix::DataType::Int64) {
                endPos = pos + static_cast<double>(extent.get<int>(i));
            } else {
                throw std::runtime_error("Unexpected DataType for the extent, expect double or integer!");
            }
            size_t c = positionToIndex(endPos, unit, dimension) - data_offset[i];
            data_count[i] = (c > 1) ? c : 1;
        }
    }

    offsets = data_offset;
    counts = data_count;
}

bool positionInData(const DataArray &data, const NDSize &position) {
    NDSize data_size = data.dataExtent();
    bool valid = true;

    if (!(data_size.size() == position.size())) {
        return false;
    }
    for (size_t i = 0; i < data_size.size(); i++) {
        valid &= position[i] < data_size[i];
    }
    return valid;
}

bool positionAndExtentInData(const DataArray &data, const NDSize &position, const NDSize &count) {
    NDSize pos = position + count;
    pos -= 1;
    return positionInData(data, pos);
}

DataView retrieveData(const MultiTag &tag, size_t position_index, size_t reference_index) {
    DataArray positions = tag.positions();
    DataArray extents = tag.extents();
    vector<DataArray> refs = tag.references();

    if (refs.size() == 0) {
        throw nix::OutOfBounds("There are no references in this tag!", 0);
    }
    if (position_index >= positions.dataExtent()[0] ||
        (extents && position_index >= extents.dataExtent()[0])) {
        throw nix::OutOfBounds("Index out of bounds of positions or extents!", 0);
    }
    if (!(reference_index < tag.referenceCount())) {
        throw nix::OutOfBounds("Reference index out of bounds.", 0);
    }

    size_t dimension_count = refs[reference_index].dimensionCount();
    if (positions.dataExtent().size() == 1 && dimension_count != 1) {
        throw nix::IncompatibleDimensions("Number of dimensions in position or extent do not match dimensionality of data",
                                          "util::retrieveData");
    } else if (positions.dataExtent().size() > 1) {
        if (positions.dataExtent()[1] > dimension_count ||
            (extents && extents.dataExtent()[1] > dimension_count)) {
            throw nix::IncompatibleDimensions("Number of dimensions in position or extent do not match dimensionality of data",
                                              "util::retrieveData");
        }
    }

    NDSize offset, count;
    getOffsetAndCount(tag, refs[reference_index], position_index, offset, count);

    if (!positionAndExtentInData(refs[reference_index], offset, count)) {
        throw nix::OutOfBounds("References data slice out of the extent of the DataArray!", 0);
    }
    DataView io = DataView(refs[reference_index], count, offset);
    return io;
}

DataView retrieveData(const Tag &tag, size_t reference_index) {
    vector<double> positions = tag.position();
    vector<double> extents = tag.extent();
    vector<DataArray> refs = tag.references();
    if (refs.size() == 0) {
        throw nix::OutOfBounds("There are no references in this tag!", 0);
    }
    if (!(reference_index < tag.referenceCount())) {
        throw nix::OutOfBounds("Reference index out of bounds.", 0);
    }
    size_t dimension_count = refs[reference_index].dimensionCount();
    if (positions.size() != dimension_count || (extents.size() > 0 && extents.size() != dimension_count)) {
        throw nix::IncompatibleDimensions("Number of dimensions in position or extent do not match dimensionality of data","util::retrieveData");
    }

    NDSize offset, count;
    getOffsetAndCount(tag, refs[reference_index], offset, count);
    if (!positionAndExtentInData(refs[reference_index], offset, count)) {
        throw nix::OutOfBounds("Referenced data slice out of the extent of the DataArray!", 0);
    }
    DataView io = DataView(refs[reference_index], count, offset);
    return io;
}

DataView retrieveFeatureData(const Tag &tag, size_t feature_index) {
    if (tag.featureCount() == 0) {
        throw nix::OutOfBounds("There are no features associated with this tag!", 0);
    }
    if (feature_index > tag.featureCount()) {
        throw nix::OutOfBounds("Feature index out of bounds.", 0);
    }
    Feature feat = tag.getFeature(feature_index);
    DataArray data = feat.data();
    if (data == nix::none) {
        throw nix::UninitializedEntity();
        //return NDArray(nix::DataType::Float,{0});
    }
    if (feat.linkType() == nix::LinkType::Tagged) {
        NDSize offset, count;
        getOffsetAndCount(tag, data, offset, count);
        if (!positionAndExtentInData(data, offset, count)) {
            throw nix::OutOfBounds("Requested data slice out of the extent of the Feature!", 0);
        }
        DataView io = DataView(data, count, offset);
        return io;
    }
    // for untagged and indexed return the full data
    NDSize offset(data.dataExtent().size(), 0);
    DataView io = DataView(data, data.dataExtent(), offset);
    return io;
}

DataView retrieveFeatureData(const MultiTag &tag, size_t position_index, size_t feature_index) {
    if (tag.featureCount() == 0) {
       throw nix::OutOfBounds("There are no features associated with this tag!", 0);
    }
    if (feature_index >= tag.featureCount()) {
        throw nix::OutOfBounds("Feature index out of bounds.", 0);
    }
    Feature feat = tag.getFeature(feature_index);
    DataArray data = feat.data();
    if (data == nix::none) {
        throw nix::UninitializedEntity();
        //return NDArray(nix::DataType::Float,{0});
    }
    if (feat.linkType() == nix::LinkType::Tagged) {
        NDSize offset, count;
        getOffsetAndCount(tag, data, position_index, offset, count);

        if (!positionAndExtentInData(data, offset, count)) {
            throw nix::OutOfBounds("Requested data slice out of the extent of the Feature!", 0);
        }
        DataView io = DataView(data, count, offset);
        return io;
    } else if (feat.linkType() == nix::LinkType::Indexed) {
        //FIXME does the feature data to have a setdimension in the first dimension for the indexed case?
        //For now it will just be a slice across the first dim.
        if (position_index > data.dataExtent()[0]){
            throw nix::OutOfBounds("Position is larger than the data stored in the feature.", 0);
        }
        NDSize offset(data.dataExtent().size(), 0);
        offset[0] = position_index;
        NDSize count(data.dataExtent());
        count[0] = 1;

        if (!positionAndExtentInData(data, offset, count)) {
            throw nix::OutOfBounds("Requested data slice out of the extent of the Feature!", 0);
        }
        DataView io = DataView(data, count, offset);
        return io;
    }
    // FIXME is this expected behavior? In the untagged case all data is returned
    NDSize offset(data.dataExtent().size(), 0);
    DataView io = DataView(data, data.dataExtent(), offset);
    return io;
}

} // namespace util
} // namespace nix
<commit_msg>[dataAccess] allow any numeric data type for position and extent<commit_after>// Copyright (c) 2013, German Neuroinformatics Node (G-Node)
//
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted under the terms of the BSD License. See
// LICENSE file in the root of the Project.

#include <string>
#include <cstdlib>
#include <cmath>
#include <algorithm>

#include <boost/optional.hpp>

#include <nix/util/util.hpp>
#include <nix/util/dataAccess.hpp>

using namespace std;

namespace nix {
namespace util {

int positionToIndex(double position, const string &unit, const Dimension &dimension) {
    if (dimension.dimensionType() == nix::DimensionType::Sample) {
        SampledDimension dim;
        dim = dimension;
        return positionToIndex(position, unit, dim);
    } else if (dimension.dimensionType() == nix::DimensionType::Set) {
        SetDimension dim;
        dim = dimension;
        return positionToIndex(position, unit, dim);
    } else {
        RangeDimension dim;
        dim = dimension;
        return positionToIndex(position, unit, dim);
    }
}

size_t positionToIndex(double position, const string &unit, const SampledDimension &dimension) {
    size_t index;
    boost::optional<string> dim_unit = dimension.unit();
    double scaling = 1.0;
    if (!dim_unit && unit != "none") {
        throw nix::IncompatibleDimensions("Units of position and SampledDimension must both be given!", "nix::util::positionToIndex");
    }
    if (dim_unit && unit != "none") {
        try {
            scaling = util::getSIScaling(unit, *dim_unit);
        } catch (...) {
            throw nix::IncompatibleDimensions("Cannot apply a position with unit to a SetDimension", "nix::util::positionToIndex");
        }
    }
    index = dimension.indexOf(position * scaling);
    return index;
}

size_t positionToIndex(double position, const string &unit, const SetDimension &dimension) {
    size_t index;
    index = static_cast<size_t>(round(position));
    if (unit.length() > 0 && unit != "none") {
        throw nix::IncompatibleDimensions("Cannot apply a position with unit to a SetDimension", "nix::util::positionToIndex");
    }

    if (dimension.labels().size() > 0 && index > dimension.labels().size()) {
        throw nix::OutOfBounds("Position is out of bounds in setDimension.", static_cast<int>(position));
    }
    return index;
}

size_t positionToIndex(double position, const string &unit, const RangeDimension &dimension) {
    size_t index;
    boost::optional<string> dim_unit = dimension.unit();
    double scaling = 1.0;

    if (dim_unit && unit != "none") {
        try {
            scaling = util::getSIScaling(unit, *dim_unit);
        } catch (...) {
            throw nix::IncompatibleDimensions("Provided units are not scalable!", "nix::util::positionToIndex");
        }
    }
    vector<double> ticks = dimension.ticks();
    if (position*scaling < *ticks.begin()) {
        return 0;
    } else if (position*scaling > *prev(ticks.end())) {
        return prev(ticks.end()) - ticks.begin();
    }
    vector<double>::iterator low = std::lower_bound (ticks.begin(), ticks.end(), position * scaling);
    if (*low == position) {
        return low - ticks.begin();
    }
    if (low != ticks.begin() && *low != position * scaling) {
        double diff_low, diff_before;
        diff_low = fabs(*low - position);
        diff_before = fabs(*(std::prev(low)) - position * scaling);
        if (diff_low < diff_before) {
            index = low - ticks.begin();
        } else {
            index = low - ticks.begin() - 1;
        }
        return index;
    } else {
        return low - ticks.begin();
    }
}

void getOffsetAndCount(const Tag &tag, const DataArray &array, NDSize &offset, NDSize &count) {
    vector<double> position = tag.position();
    vector<double> extent = tag.extent();
    vector<string> units = tag.units();
    NDSize temp_offset(position.size());
    NDSize temp_count(position.size(), 1);

    if (array.dimensionCount() != position.size() || (extent.size() > 0 && extent.size() != array.dimensionCount())) {
        throw std::runtime_error("Dimensionality of position or extent vector does not match dimensionality of data!");
    }
    for (size_t i = 0; i < position.size(); ++i) {
        Dimension dim = array.getDimension(i+1);
        temp_offset[i] = positionToIndex(position[i], i >= units.size() ? "none" : units[i], dim);
        if (i < extent.size()) {
            size_t c = positionToIndex(position[i] + extent[i], i >= units.size() ? "none" : units[i], dim) - temp_offset[i];
            temp_count[i] = (c > 1) ? c : 1;
        }
    }
    offset = temp_offset;
    count = temp_count;
}

void getOffsetAndCount(const MultiTag &tag, const DataArray &array, size_t index, NDSize &offsets, NDSize &counts) {
    DataArray positions = tag.positions();
    DataArray extents = tag.extents();
    NDSize position_size, extent_size;
    size_t dimension_count = array.dimensionCount();

    if (positions) {
        position_size = positions.dataExtent();
    }

    if (extents) {
        extent_size = extents.dataExtent();
    }

    if (!positions || index >= position_size[0]) {
        throw nix::OutOfBounds("Index out of bounds of positions!", 0);
    }

    if (extents && index >= extent_size[0]) {
        throw nix::OutOfBounds("Index out of bounds of positions or extents!", 0);
    }

    if (position_size.size() == 1 && dimension_count != 1) {
        throw nix::IncompatibleDimensions("Number of dimensions in positions does not match dimensionality of data",
                                          "util::getOffsetAndCount");
    }

    if (position_size.size() > 1 && position_size[1] > dimension_count) {
        throw nix::IncompatibleDimensions("Number of dimensions in positions does not match dimensionality of data",
                                          "util::getOffsetAndCount");
    }

    if (extents && extent_size.size() > 1 && extent_size[1] > dimension_count) {
        throw nix::IncompatibleDimensions("Number of dimensions in extents does not match dimensionality of data",
                                          "util::getOffsetAndCount");
    }

    NDSize temp_offset = NDSize{static_cast<NDSize::value_type>(index), static_cast<NDSize::value_type>(0)};
    NDSize temp_count{static_cast<NDSize::value_type>(1), static_cast<NDSize::value_type>(dimension_count)};
    vector<double> offset;
    positions.getData(offset, temp_count, temp_offset);

    NDSize data_offset(dimension_count, static_cast<size_t>(0));
    NDSize data_count(dimension_count, static_cast<size_t>(1));
    vector<string> units = tag.units();

    for (size_t i = 0; i < offset.size(); ++i) {
        Dimension dimension = array.getDimension(i+1);
        string unit = "none";
        if (i <= units.size() && units.size() > 0) {
            unit = units[i];
        }
        data_offset[i] = positionToIndex(offset[i], unit, dimension);
    }

    if (extents) {
        vector<double> extent;
        extents.getData(extent, temp_count, temp_offset);
        for (size_t i = 0; i < extent.size(); ++i) {
            Dimension dimension = array.getDimension(i+1);
            string unit = "none";
            if (i <= units.size() && units.size() > 0) {
                unit = units[i];
            }
            size_t c = positionToIndex(offset[i] + extent[i], unit, dimension) - data_offset[i];
            data_count[i] = (c > 1) ? c : 1;
        }
    }

    offsets = data_offset;
    counts = data_count;
}

bool positionInData(const DataArray &data, const NDSize &position) {
    NDSize data_size = data.dataExtent();
    bool valid = true;

    if (!(data_size.size() == position.size())) {
        return false;
    }
    for (size_t i = 0; i < data_size.size(); i++) {
        valid &= position[i] < data_size[i];
    }
    return valid;
}

bool positionAndExtentInData(const DataArray &data, const NDSize &position, const NDSize &count) {
    NDSize pos = position + count;
    pos -= 1;
    return positionInData(data, pos);
}

DataView retrieveData(const MultiTag &tag, size_t position_index, size_t reference_index) {
    DataArray positions = tag.positions();
    DataArray extents = tag.extents();
    vector<DataArray> refs = tag.references();

    if (refs.size() == 0) {
        throw nix::OutOfBounds("There are no references in this tag!", 0);
    }
    if (position_index >= positions.dataExtent()[0] ||
        (extents && position_index >= extents.dataExtent()[0])) {
        throw nix::OutOfBounds("Index out of bounds of positions or extents!", 0);
    }
    if (!(reference_index < tag.referenceCount())) {
        throw nix::OutOfBounds("Reference index out of bounds.", 0);
    }

    size_t dimension_count = refs[reference_index].dimensionCount();
    if (positions.dataExtent().size() == 1 && dimension_count != 1) {
        throw nix::IncompatibleDimensions("Number of dimensions in position or extent do not match dimensionality of data",
                                          "util::retrieveData");
    } else if (positions.dataExtent().size() > 1) {
        if (positions.dataExtent()[1] > dimension_count ||
            (extents && extents.dataExtent()[1] > dimension_count)) {
            throw nix::IncompatibleDimensions("Number of dimensions in position or extent do not match dimensionality of data",
                                              "util::retrieveData");
        }
    }

    NDSize offset, count;
    getOffsetAndCount(tag, refs[reference_index], position_index, offset, count);

    if (!positionAndExtentInData(refs[reference_index], offset, count)) {
        throw nix::OutOfBounds("References data slice out of the extent of the DataArray!", 0);
    }
    DataView io = DataView(refs[reference_index], count, offset);
    return io;
}

DataView retrieveData(const Tag &tag, size_t reference_index) {
    vector<double> positions = tag.position();
    vector<double> extents = tag.extent();
    vector<DataArray> refs = tag.references();
    if (refs.size() == 0) {
        throw nix::OutOfBounds("There are no references in this tag!", 0);
    }
    if (!(reference_index < tag.referenceCount())) {
        throw nix::OutOfBounds("Reference index out of bounds.", 0);
    }
    size_t dimension_count = refs[reference_index].dimensionCount();
    if (positions.size() != dimension_count || (extents.size() > 0 && extents.size() != dimension_count)) {
        throw nix::IncompatibleDimensions("Number of dimensions in position or extent do not match dimensionality of data","util::retrieveData");
    }

    NDSize offset, count;
    getOffsetAndCount(tag, refs[reference_index], offset, count);
    if (!positionAndExtentInData(refs[reference_index], offset, count)) {
        throw nix::OutOfBounds("Referenced data slice out of the extent of the DataArray!", 0);
    }
    DataView io = DataView(refs[reference_index], count, offset);
    return io;
}

DataView retrieveFeatureData(const Tag &tag, size_t feature_index) {
    if (tag.featureCount() == 0) {
        throw nix::OutOfBounds("There are no features associated with this tag!", 0);
    }
    if (feature_index > tag.featureCount()) {
        throw nix::OutOfBounds("Feature index out of bounds.", 0);
    }
    Feature feat = tag.getFeature(feature_index);
    DataArray data = feat.data();
    if (data == nix::none) {
        throw nix::UninitializedEntity();
        //return NDArray(nix::DataType::Float,{0});
    }
    if (feat.linkType() == nix::LinkType::Tagged) {
        NDSize offset, count;
        getOffsetAndCount(tag, data, offset, count);
        if (!positionAndExtentInData(data, offset, count)) {
            throw nix::OutOfBounds("Requested data slice out of the extent of the Feature!", 0);
        }
        DataView io = DataView(data, count, offset);
        return io;
    }
    // for untagged and indexed return the full data
    NDSize offset(data.dataExtent().size(), 0);
    DataView io = DataView(data, data.dataExtent(), offset);
    return io;
}

DataView retrieveFeatureData(const MultiTag &tag, size_t position_index, size_t feature_index) {
    if (tag.featureCount() == 0) {
       throw nix::OutOfBounds("There are no features associated with this tag!", 0);
    }
    if (feature_index >= tag.featureCount()) {
        throw nix::OutOfBounds("Feature index out of bounds.", 0);
    }
    Feature feat = tag.getFeature(feature_index);
    DataArray data = feat.data();
    if (data == nix::none) {
        throw nix::UninitializedEntity();
        //return NDArray(nix::DataType::Float,{0});
    }
    if (feat.linkType() == nix::LinkType::Tagged) {
        NDSize offset, count;
        getOffsetAndCount(tag, data, position_index, offset, count);

        if (!positionAndExtentInData(data, offset, count)) {
            throw nix::OutOfBounds("Requested data slice out of the extent of the Feature!", 0);
        }
        DataView io = DataView(data, count, offset);
        return io;
    } else if (feat.linkType() == nix::LinkType::Indexed) {
        //FIXME does the feature data to have a setdimension in the first dimension for the indexed case?
        //For now it will just be a slice across the first dim.
        if (position_index > data.dataExtent()[0]){
            throw nix::OutOfBounds("Position is larger than the data stored in the feature.", 0);
        }
        NDSize offset(data.dataExtent().size(), 0);
        offset[0] = position_index;
        NDSize count(data.dataExtent());
        count[0] = 1;

        if (!positionAndExtentInData(data, offset, count)) {
            throw nix::OutOfBounds("Requested data slice out of the extent of the Feature!", 0);
        }
        DataView io = DataView(data, count, offset);
        return io;
    }
    // FIXME is this expected behavior? In the untagged case all data is returned
    NDSize offset(data.dataExtent().size(), 0);
    DataView io = DataView(data, data.dataExtent(), offset);
    return io;
}

} // namespace util
} // namespace nix
<|endoftext|>


<commit_before>/*
 * Copyright 2011-2016 Blender Foundation
 *
 * 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 "util_debug.h"

#include <stdlib.h>

#include "util_logging.h"
#include "util_string.h"

CCL_NAMESPACE_BEGIN

DebugFlags::CPU::CPU()
  : avx2(true),
    avx(true),
    sse41(true),
    sse3(true),
    sse2(true)
{
	reset();
}

void DebugFlags::CPU::reset()
{
#define STRINGIFY(x) #x
#define CHECK_CPU_FLAGS(flag, env) \
	do { \
		flag = (getenv(env) == NULL); \
		if(!flag) { \
			VLOG(1) << "Disabling " << STRINGIFY(flag) << " instruction set."; \
		} \
	} while(0)

	CHECK_CPU_FLAGS(avx2, "CYCLES_CPU_NO_AVX2");
	CHECK_CPU_FLAGS(avx, "CYCLES_CPU_NO_AVX");
	CHECK_CPU_FLAGS(sse41, "CYCLES_CPU_NO_SSE41");
	CHECK_CPU_FLAGS(sse3, "CYCLES_CPU_NO_SSE3");
	CHECK_CPU_FLAGS(sse2, "CYCLES_CPU_NO_SSE2");

#undef STRINGIFY
#undef CHECK_CPU_FLAGS
}

DebugFlags::OpenCL::OpenCL()
  : device_type(DebugFlags::OpenCL::DEVICE_ALL),
    kernel_type(DebugFlags::OpenCL::KERNEL_DEFAULT),
    debug(false)
{
	reset();
}

void DebugFlags::OpenCL::reset()
{
	/* Initialize device type from environment variables. */
	device_type = DebugFlags::OpenCL::DEVICE_ALL;
	char *device = getenv("CYCLES_OPENCL_TEST");
	if(device) {
		if(strcmp(device, "NONE") == 0) {
			device_type = DebugFlags::OpenCL::DEVICE_NONE;
		}
		else if(strcmp(device, "ALL") == 0) {
			device_type = DebugFlags::OpenCL::DEVICE_ALL;
		}
		else if(strcmp(device, "DEFAULT") == 0) {
			device_type = DebugFlags::OpenCL::DEVICE_DEFAULT;
		}
		else if(strcmp(device, "CPU") == 0) {
			device_type = DebugFlags::OpenCL::DEVICE_CPU;
		}
		else if(strcmp(device, "GPU") == 0) {
			device_type = DebugFlags::OpenCL::DEVICE_GPU;
		}
		else if(strcmp(device, "ACCELERATOR") == 0) {
			device_type = DebugFlags::OpenCL::DEVICE_ACCELERATOR;
		}
	}
	/* Initialize kernel type from environment variables. */
	kernel_type = DebugFlags::OpenCL::KERNEL_DEFAULT;
	if(getenv("CYCLES_OPENCL_MEGA_KERNEL_TEST") != NULL) {
		kernel_type = DebugFlags::OpenCL::KERNEL_MEGA;
	}
	else if(getenv("CYCLES_OPENCL_MEGA_KERNEL_TEST") != NULL) {
		kernel_type = DebugFlags::OpenCL::KERNEL_SPLIT;
	}
	/* Initialize other flags from environment variables. */
	debug = (getenv("CYCLES_OPENCL_DEBUG") != NULL);
}

DebugFlags::DebugFlags()
{
	/* Nothing for now. */
}

void DebugFlags::reset()
{
	cpu.reset();
	opencl.reset();
}

std::ostream& operator <<(std::ostream &os,
                          const DebugFlagsRef debug_flags)
{
	os << "CPU flags:\n"
	   << "  AVX2   : " << string_from_bool(debug_flags.cpu.avx2)  << "\n"
	   << "  AVX    : " << string_from_bool(debug_flags.cpu.avx)   << "\n"
	   << "  SSE4.1 : " << string_from_bool(debug_flags.cpu.sse41) << "\n"
	   << "  SSE3   : " << string_from_bool(debug_flags.cpu.sse3)  << "\n"
	   << "  SSE2   : " << string_from_bool(debug_flags.cpu.sse2)  << "\n";

	const char *opencl_device_type,
	           *opencl_kernel_type;
	switch(debug_flags.opencl.device_type) {
		case DebugFlags::OpenCL::DEVICE_NONE:
			opencl_device_type = "NONE";
			break;
		case DebugFlags::OpenCL::DEVICE_ALL:
			opencl_device_type = "ALL";
			break;
		case DebugFlags::OpenCL::DEVICE_DEFAULT:
			opencl_device_type = "DEFAULT";
			break;
		case DebugFlags::OpenCL::DEVICE_CPU:
			opencl_device_type = "CPU";
			break;
		case DebugFlags::OpenCL::DEVICE_GPU:
			opencl_device_type = "GPU";
			break;
		case DebugFlags::OpenCL::DEVICE_ACCELERATOR:
			opencl_device_type = "ACCELERATOR";
			break;
	}
	switch(debug_flags.opencl.kernel_type) {
		case DebugFlags::OpenCL::KERNEL_DEFAULT:
			opencl_kernel_type = "DEFAULT";
			break;
		case DebugFlags::OpenCL::KERNEL_MEGA:
			opencl_kernel_type = "MEGA";
			break;
		case DebugFlags::OpenCL::KERNEL_SPLIT:
			opencl_kernel_type = "SPLIT";
			break;
	}
	os << "OpenCL flags:\n"
	   << "  Device type : " << opencl_device_type << "\n"
	   << "  Kernel type : " << opencl_kernel_type << "\n"
	   << "  Debug       : " << string_from_bool(debug_flags.opencl.debug)
	   << "\n";
	return os;
}

CCL_NAMESPACE_END
<commit_msg>Fix typo in the debug panel commit<commit_after>/*
 * Copyright 2011-2016 Blender Foundation
 *
 * 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 "util_debug.h"

#include <stdlib.h>

#include "util_logging.h"
#include "util_string.h"

CCL_NAMESPACE_BEGIN

DebugFlags::CPU::CPU()
  : avx2(true),
    avx(true),
    sse41(true),
    sse3(true),
    sse2(true)
{
	reset();
}

void DebugFlags::CPU::reset()
{
#define STRINGIFY(x) #x
#define CHECK_CPU_FLAGS(flag, env) \
	do { \
		flag = (getenv(env) == NULL); \
		if(!flag) { \
			VLOG(1) << "Disabling " << STRINGIFY(flag) << " instruction set."; \
		} \
	} while(0)

	CHECK_CPU_FLAGS(avx2, "CYCLES_CPU_NO_AVX2");
	CHECK_CPU_FLAGS(avx, "CYCLES_CPU_NO_AVX");
	CHECK_CPU_FLAGS(sse41, "CYCLES_CPU_NO_SSE41");
	CHECK_CPU_FLAGS(sse3, "CYCLES_CPU_NO_SSE3");
	CHECK_CPU_FLAGS(sse2, "CYCLES_CPU_NO_SSE2");

#undef STRINGIFY
#undef CHECK_CPU_FLAGS
}

DebugFlags::OpenCL::OpenCL()
  : device_type(DebugFlags::OpenCL::DEVICE_ALL),
    kernel_type(DebugFlags::OpenCL::KERNEL_DEFAULT),
    debug(false)
{
	reset();
}

void DebugFlags::OpenCL::reset()
{
	/* Initialize device type from environment variables. */
	device_type = DebugFlags::OpenCL::DEVICE_ALL;
	char *device = getenv("CYCLES_OPENCL_TEST");
	if(device) {
		if(strcmp(device, "NONE") == 0) {
			device_type = DebugFlags::OpenCL::DEVICE_NONE;
		}
		else if(strcmp(device, "ALL") == 0) {
			device_type = DebugFlags::OpenCL::DEVICE_ALL;
		}
		else if(strcmp(device, "DEFAULT") == 0) {
			device_type = DebugFlags::OpenCL::DEVICE_DEFAULT;
		}
		else if(strcmp(device, "CPU") == 0) {
			device_type = DebugFlags::OpenCL::DEVICE_CPU;
		}
		else if(strcmp(device, "GPU") == 0) {
			device_type = DebugFlags::OpenCL::DEVICE_GPU;
		}
		else if(strcmp(device, "ACCELERATOR") == 0) {
			device_type = DebugFlags::OpenCL::DEVICE_ACCELERATOR;
		}
	}
	/* Initialize kernel type from environment variables. */
	kernel_type = DebugFlags::OpenCL::KERNEL_DEFAULT;
	if(getenv("CYCLES_OPENCL_MEGA_KERNEL_TEST") != NULL) {
		kernel_type = DebugFlags::OpenCL::KERNEL_MEGA;
	}
	else if(getenv("CYCLES_OPENCL_SPLITKERNEL_TEST") != NULL) {
		kernel_type = DebugFlags::OpenCL::KERNEL_SPLIT;
	}
	/* Initialize other flags from environment variables. */
	debug = (getenv("CYCLES_OPENCL_DEBUG") != NULL);
}

DebugFlags::DebugFlags()
{
	/* Nothing for now. */
}

void DebugFlags::reset()
{
	cpu.reset();
	opencl.reset();
}

std::ostream& operator <<(std::ostream &os,
                          const DebugFlagsRef debug_flags)
{
	os << "CPU flags:\n"
	   << "  AVX2   : " << string_from_bool(debug_flags.cpu.avx2)  << "\n"
	   << "  AVX    : " << string_from_bool(debug_flags.cpu.avx)   << "\n"
	   << "  SSE4.1 : " << string_from_bool(debug_flags.cpu.sse41) << "\n"
	   << "  SSE3   : " << string_from_bool(debug_flags.cpu.sse3)  << "\n"
	   << "  SSE2   : " << string_from_bool(debug_flags.cpu.sse2)  << "\n";

	const char *opencl_device_type,
	           *opencl_kernel_type;
	switch(debug_flags.opencl.device_type) {
		case DebugFlags::OpenCL::DEVICE_NONE:
			opencl_device_type = "NONE";
			break;
		case DebugFlags::OpenCL::DEVICE_ALL:
			opencl_device_type = "ALL";
			break;
		case DebugFlags::OpenCL::DEVICE_DEFAULT:
			opencl_device_type = "DEFAULT";
			break;
		case DebugFlags::OpenCL::DEVICE_CPU:
			opencl_device_type = "CPU";
			break;
		case DebugFlags::OpenCL::DEVICE_GPU:
			opencl_device_type = "GPU";
			break;
		case DebugFlags::OpenCL::DEVICE_ACCELERATOR:
			opencl_device_type = "ACCELERATOR";
			break;
	}
	switch(debug_flags.opencl.kernel_type) {
		case DebugFlags::OpenCL::KERNEL_DEFAULT:
			opencl_kernel_type = "DEFAULT";
			break;
		case DebugFlags::OpenCL::KERNEL_MEGA:
			opencl_kernel_type = "MEGA";
			break;
		case DebugFlags::OpenCL::KERNEL_SPLIT:
			opencl_kernel_type = "SPLIT";
			break;
	}
	os << "OpenCL flags:\n"
	   << "  Device type : " << opencl_device_type << "\n"
	   << "  Kernel type : " << opencl_kernel_type << "\n"
	   << "  Debug       : " << string_from_bool(debug_flags.opencl.debug)
	   << "\n";
	return os;
}

CCL_NAMESPACE_END
<|endoftext|>


<commit_before>/****************************************************************************
 *
 *   Copyright (c) 2017-2019 PX4 Development Team. All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. 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.
 * 3. Neither the name PX4 nor the names of its contributors may be
 *    used to endorse or promote products derived from this software
 *    without specific prior written permission.
 *
 * 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 OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
 * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 *
 ****************************************************************************/

#include "CameraFeedback.hpp"

CameraFeedback::CameraFeedback() :
	ModuleParams(nullptr),
	WorkItem(MODULE_NAME, px4::wq_configurations::hp_default)
{
}

bool
CameraFeedback::init()
{
	if (!_trigger_sub.registerCallback()) {
		PX4_ERR("camera_trigger callback registration failed!");
		return false;
	}

	return true;
}

void
CameraFeedback::Run()
{
	if (should_exit()) {
		_trigger_sub.unregisterCallback();
		exit_and_cleanup();
		return;
	}

	camera_trigger_s trig{};

	if (_trigger_sub.update(&trig)) {

		// update geotagging subscriptions
		vehicle_global_position_s gpos{};
		_gpos_sub.copy(&gpos);

		vehicle_attitude_s att{};
		_att_sub.copy(&att);

		if (trig.timestamp == 0 ||
		    gpos.timestamp == 0 ||
		    att.timestamp == 0) {

			// reject until we have valid data
			return;
		}

		camera_capture_s capture{};

		// Fill timestamps
		capture.timestamp = trig.timestamp;
		capture.timestamp_utc = trig.timestamp_utc;

		// Fill image sequence
		capture.seq = trig.seq;

		// Fill position data
		capture.lat = gpos.lat;
		capture.lon = gpos.lon;
		capture.alt = gpos.alt;

		if (gpos.terrain_alt_valid) {
			capture.ground_distance = gpos.alt - gpos.terrain_alt;

		} else {
			capture.ground_distance = -1.0f;
		}

		// Fill attitude data
		// TODO : this needs to be rotated by camera orientation or set to gimbal orientation when available
		capture.q[0] = att.q[0];
		capture.q[1] = att.q[1];
		capture.q[2] = att.q[2];
		capture.q[3] = att.q[3];

		// Indicate whether capture feedback from camera is available
		// What is case 0 for capture.result?
		if (!_param_camera_capture_feedback.get()) {
			capture.result = -1;

		} else {
			capture.result = 1;
		}

		_capture_pub.publish(capture);
	}
}

int
CameraFeedback::task_spawn(int argc, char *argv[])
{
	CameraFeedback *instance = new CameraFeedback();

	if (instance) {
		_object.store(instance);
		_task_id = task_id_is_work_queue;

		if (instance->init()) {
			return PX4_OK;
		}

	} else {
		PX4_ERR("alloc failed");
	}

	delete instance;
	_object.store(nullptr);
	_task_id = -1;

	return PX4_ERROR;
}

int
CameraFeedback::custom_command(int argc, char *argv[])
{
	return print_usage("unknown command");
}

int
CameraFeedback::print_usage(const char *reason)
{
	if (reason) {
		PX4_WARN("%s\n", reason);
	}

	PRINT_MODULE_DESCRIPTION(
		R"DESCR_STR(
### Description

)DESCR_STR");

	PRINT_MODULE_USAGE_NAME("camera_feedback", "system");
	PRINT_MODULE_USAGE_COMMAND("start");
	PRINT_MODULE_USAGE_DEFAULT_COMMANDS();

	return 0;
}

extern "C" __EXPORT int camera_feedback_main(int argc, char *argv[])
{
	return CameraFeedback::main(argc, argv);
}
<commit_msg>capture.result<commit_after>/****************************************************************************
 *
 *   Copyright (c) 2017-2019 PX4 Development Team. All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. 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.
 * 3. Neither the name PX4 nor the names of its contributors may be
 *    used to endorse or promote products derived from this software
 *    without specific prior written permission.
 *
 * 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 OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
 * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 *
 ****************************************************************************/

#include "CameraFeedback.hpp"

CameraFeedback::CameraFeedback() :
	ModuleParams(nullptr),
	WorkItem(MODULE_NAME, px4::wq_configurations::hp_default)
{
}

bool
CameraFeedback::init()
{
	if (!_trigger_sub.registerCallback()) {
		PX4_ERR("camera_trigger callback registration failed!");
		return false;
	}

	return true;
}

void
CameraFeedback::Run()
{
	if (should_exit()) {
		_trigger_sub.unregisterCallback();
		exit_and_cleanup();
		return;
	}

	camera_trigger_s trig{};

	if (_trigger_sub.update(&trig)) {

		// update geotagging subscriptions
		vehicle_global_position_s gpos{};
		_gpos_sub.copy(&gpos);

		vehicle_attitude_s att{};
		_att_sub.copy(&att);

		if (trig.timestamp == 0 ||
		    gpos.timestamp == 0 ||
		    att.timestamp == 0) {

			// reject until we have valid data
			return;
		}

		camera_capture_s capture{};

		// Fill timestamps
		capture.timestamp = trig.timestamp;
		capture.timestamp_utc = trig.timestamp_utc;

		// Fill image sequence
		capture.seq = trig.seq;

		// Fill position data
		capture.lat = gpos.lat;
		capture.lon = gpos.lon;
		capture.alt = gpos.alt;

		if (gpos.terrain_alt_valid) {
			capture.ground_distance = gpos.alt - gpos.terrain_alt;

		} else {
			capture.ground_distance = -1.0f;
		}

		// Fill attitude data
		// TODO : this needs to be rotated by camera orientation or set to gimbal orientation when available
		capture.q[0] = att.q[0];
		capture.q[1] = att.q[1];
		capture.q[2] = att.q[2];
		capture.q[3] = att.q[3];

		// Indicate whether capture feedback from camera is available
		// What is case 0 for capture.result?
		if (!_param_camera_capture_feedback.get()) {
			capture.result = 0;

		} else {
			capture.result = 1;
		}

		_capture_pub.publish(capture);
	}
}

int
CameraFeedback::task_spawn(int argc, char *argv[])
{
	CameraFeedback *instance = new CameraFeedback();

	if (instance) {
		_object.store(instance);
		_task_id = task_id_is_work_queue;

		if (instance->init()) {
			return PX4_OK;
		}

	} else {
		PX4_ERR("alloc failed");
	}

	delete instance;
	_object.store(nullptr);
	_task_id = -1;

	return PX4_ERROR;
}

int
CameraFeedback::custom_command(int argc, char *argv[])
{
	return print_usage("unknown command");
}

int
CameraFeedback::print_usage(const char *reason)
{
	if (reason) {
		PX4_WARN("%s\n", reason);
	}

	PRINT_MODULE_DESCRIPTION(
		R"DESCR_STR(
### Description

)DESCR_STR");

	PRINT_MODULE_USAGE_NAME("camera_feedback", "system");
	PRINT_MODULE_USAGE_COMMAND("start");
	PRINT_MODULE_USAGE_DEFAULT_COMMANDS();

	return 0;
}

extern "C" __EXPORT int camera_feedback_main(int argc, char *argv[])
{
	return CameraFeedback::main(argc, argv);
}
<|endoftext|>


<commit_before>/*
    Copyright (C) 1999 by Jorrit Tyberghein

    This library is free software; you can redistribute it and/or
    modify it under the terms of the GNU Library General Public
    License as published by the Free Software Foundation; either
    version 2 of the License, or (at your option) any later version.

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

    You should have received a copy of the GNU Library General Public
    License along with this library; if not, write to the Free
    Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/

#include "sysdef.h"
#include "csengine/terrain.h"
#include "csengine/pol2d.h"
#include "csengine/texture.h"
#include "csterr/ddgtmesh.h"
#include "csterr/ddgbtree.h"
#include "csgeom/math2d.h"
#include "csgeom/math3d.h"
#include "csgeom/polyclip.h"
#include "igraph3d.h"

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

CSOBJTYPE_IMPL(csTerrain,csObject);

csTerrain::csTerrain () : csObject()
{
  clipbox = NULL;
  height = NULL;
  mesh = NULL;
}

csTerrain::~csTerrain ()
{
  CHK (delete mesh);
  CHK (delete height);
  CHK (delete clipbox);
}

void csTerrain::classify( ddgVector3 *p, ddgVector3 *n, ddgColor3 *c)
{
	// Steep normal
    if (fabs(n->v[1]) < _cliffangle)
		c->set(_cliff); // Cliff
    else if (p->v[1] < _beachalt)
		c->set(_beach); // Beach
    else if (p->v[1] < _grassalt)
		c->set(_grass); // Grass
    else if (p->v[1] < _treealt)
		c->set(_trees); // Trees
    else if (p->v[1] < _rockalt)
		c->set(_rock);  // Rock
    else
		c->set(_snow);  // Snow

	static int cl = 0, b=0,g=0,t=0,r=0,s=0;
    if (fabs(n->v[1]) < _cliffangle)
		cl++;
    else if (p->v[1] < _beachalt)
		b++;
    else if (p->v[1] < _grassalt)
		g++;
    else if (p->v[1] < _treealt)
		t++;
    else if (p->v[1] < _rockalt)
		r++;
    else
		s++;
}

static csRenderView *grview = NULL;
// Perform coord transformation using CS instead of DDG.
static void transformer(ddgVector3 vin, ddgVector3 *vout)
{
	if (grview)
	{
		csVector3 csw1 = grview->World2Camera( csVector3(vin.v[0],vin.v[1],vin.v[2]) );
		vout->v[0] = csw1.x;
		vout->v[1] = csw1.y;
		vout->v[2] = csw1.z;
	}
	else
	{
		vout->v[0] = vin.v[0];
		vout->v[1] = vin.v[1];
		vout->v[2] = vin.v[2];
	}
}

// Z depth queue iterator
static ddgSplayIterator		*qri;
// Z depth queue.
static ddgQueue			*qr;

bool csTerrain::Initialize (char* heightmap)
{

  CHK (height = new ddgHeightMap ());
  if (height->readTGN (heightmap))
	  height->generateHeights(257,257,5);
  CHK (mesh = new ddgTBinMesh (height));
  CHK (clipbox = new ddgBBox (ddgVector3(0,0,1),ddgVector3(640, 480, 15000)));

  float fov = 90.0;
  mesh->settransform(transformer);
  mesh->init (NULL, clipbox, fov);

	_cliff.set(175,175,175);  // Cliff
	_beach.set(200,200,50);  // Beach.
	_grass.set(95,145,70);    // Grass
	_trees.set(25,50,25);     // Trees
	_rock.set(125,125,125);      // Rock
	_snow.set(250,250,250);      // Snow

	_cliffangle = 0.2; // up component of normal vector.
	_beachalt = 0;
	_grassalt = 3;
	_treealt = 5;
	_rockalt = 7;
	_snowalt = 999;

  return true;
}

void csTerrain::Draw (csRenderView& rview, bool use_z_buf)
{
  G3DPolygonDPFX poly;

  memset (&poly, 0, sizeof(poly));
  poly.inv_aspect = rview.inv_aspect;
  poly.flat_color_r = 1;
  poly.flat_color_g = 1;
  poly.flat_color_b = 1;
  poly.txt_handle = _textureMap->GetTextureHandle ();
  rview.g3d->SetRenderState (G3DRENDERSTATE_ZBUFFERTESTENABLE, false /*use_z_buf*/);
  rview.g3d->SetRenderState (G3DRENDERSTATE_ZBUFFERFILLENABLE, true);
  rview.g3d->StartPolygonFX (poly.txt_handle, CS_FX_GOURAUD);
  grview = &rview;
  // For each frame.
  mesh->calculate ();

	// If we are not using Z-buffer...
    // For all the triangle in the visible queue, insert them in z-order.

  	if ( 1 /*!use_z_buf*/ )
	{
		mesh->qzi()->reset();
		// Clear queue.
		mesh->qz()->clear();
		mesh->qsi()->reset();
		while (!mesh->qsi()->end())
		{
			ddgTriIndex tvc = mesh->qs ()->index (mesh->qsi ()), tvp, tv0, tv1;
            float d;
			ddgTBinTree *bt = mesh->qs ()->tree (mesh->qsi ());

            tvp = ddgTBinTree::parent(tvc);
            tv0 = mesh->stri[tvc].v0;
            tv1 = mesh->stri[tvc].v1;
			ddgVector3 *p = bt->tri(tv0)->pos();
    		// Use the nearest coord of the triangle.
            d = p->v[2];
			p = bt->tri(tv1)->pos();
            if (p->v[2] < d)
                d = p->v[2];
			p = bt->tri(tvp)->pos();
            if (p->v[2] < d)
                d = p->v[2];
            mesh->qz()->ddgSplayTree::insert (bt->index(),tvc,(unsigned int)d);
			mesh->qsi ()->next ();
		}
		qri = mesh->qzi();
		qr  = mesh->qz();
	}
	else
	{
		qri = mesh->qsi ();
		qr  = mesh->qs ();
	}

   // Render
  qri->reset ();
  while (!qri->end ())
  {
    ddgTriIndex tvc = qr->index (qri );
    ddgTBinTree *bt = qr->tree (qri );

    if (!bt->tri (tvc)->vis ().flags.none)
    {

      ddgVector3 *p1, *p2, *p3;
      ddgVector3 wp1, wp2, wp3;
      ddgVector3 n1, n2, n3;
      ddgVector2 t1, t2, t3;
      ddgColor3  c1, c2, c3;
	  unsigned int tvp = bt->parent (tvc),
		  tv0 = bt->v0 (tvc),
		  tv1 = bt->v1 (tvc);
	  // Camera space coords.
	  p3 =	bt->tri(tvp)->pos();
	  p2 =	bt->tri(tv0)->pos();
	  p1 =	bt->tri(tv1)->pos();
	  // World space coords.
      bt->vertex(tvp,&wp1);
      bt->vertex(tv0,&wp2);
      bt->vertex(tv1,&wp3);
	  // Normals.
	  bt->normal(tvp,&n1);
	  bt->normal(tv0,&n2);
	  bt->normal(tv1,&n3);
      // Texture coords from 0 - N where N is size of texture.
	  bt->textureC(tvp,t1);
	  bt->textureC(tv0,t2);
	  bt->textureC(tv1,t3);
	  // Create some color scheme.
	  classify(wp1,&n1,&c1);
	  classify(wp2,&n2,&c2);
	  classify(wp3,&n3,&c3);

      float iz;
      float pz[3];
      csVector2 triangle[3];
      if (p1->v[2] < SMALL_Z) goto not_vis;
      pz[0] = 1 / p1->v[2];
      iz = rview.aspect * pz[0];
      triangle[0].x = p1->v[0] * iz + rview.shift_x;
      triangle[0].y = p1->v[1] * iz + rview.shift_x;
      if (p2->v[2] < SMALL_Z) goto not_vis;
      pz[1] = 1 / p2->v[2];
      iz = rview.aspect * pz[1];
      triangle[1].x = p2->v[0] * iz + rview.shift_x;
      triangle[1].y = p2->v[1] * iz + rview.shift_x;
      if (p3->v[2] < SMALL_Z) goto not_vis;
      pz[2] = 1 / p3->v[2];
      iz = rview.aspect * pz[2];
      triangle[2].x = p3->v[0] * iz + rview.shift_x;
      triangle[2].y = p3->v[1] * iz + rview.shift_x;

      csVector2 clipped_triangle [10];	//@@@BAD HARCODED!
      int rescount;
      if (!rview.view->Clip (triangle, clipped_triangle, 3, rescount)) goto not_vis;
      poly.num = rescount;

      poly.vertices[0].z = pz[0];
      poly.vertices[0].u = 0;
      poly.vertices[0].v = 0;
      poly.vertices[0].r = (float)c1.v[0]/255.0;
      poly.vertices[0].g = (float)c1.v[1]/255.0;
      poly.vertices[0].b = (float)c1.v[2]/255.0;

      poly.vertices[1].z = pz[1];
      poly.vertices[1].u = 1;
      poly.vertices[1].v = 0;
      poly.vertices[1].r = (float)c2.v[0]/255.0;
      poly.vertices[1].g = (float)c2.v[1]/255.0;
      poly.vertices[1].b = (float)c2.v[2]/255.0;

      poly.vertices[2].z = pz[2];
      poly.vertices[2].u = 0;
      poly.vertices[2].v = 1;
      poly.vertices[2].r = (float)c3.v[0]/255.0;
      poly.vertices[2].g = (float)c3.v[1]/255.0;
      poly.vertices[2].b = (float)c3.v[2]/255.0;

      PreparePolygonFX (&poly, clipped_triangle, rescount, triangle,
      	true);
      rview.g3d->DrawPolygonFX (poly);
    }

    not_vis:
    qri ->next ();
  }

  rview.g3d->FinishPolygonFX ();
}

<commit_msg>removed a warning<commit_after>/*
    Copyright (C) 1999 by Jorrit Tyberghein

    This library is free software; you can redistribute it and/or
    modify it under the terms of the GNU Library General Public
    License as published by the Free Software Foundation; either
    version 2 of the License, or (at your option) any later version.

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

    You should have received a copy of the GNU Library General Public
    License along with this library; if not, write to the Free
    Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/

#include "sysdef.h"
#include "csengine/terrain.h"
#include "csengine/pol2d.h"
#include "csengine/texture.h"
#include "csterr/ddgtmesh.h"
#include "csterr/ddgbtree.h"
#include "csgeom/math2d.h"
#include "csgeom/math3d.h"
#include "csgeom/polyclip.h"
#include "igraph3d.h"

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

CSOBJTYPE_IMPL(csTerrain,csObject);

csTerrain::csTerrain () : csObject()
{
  clipbox = NULL;
  height = NULL;
  mesh = NULL;
}

csTerrain::~csTerrain ()
{
  CHK (delete mesh);
  CHK (delete height);
  CHK (delete clipbox);
}

void csTerrain::classify( ddgVector3 *p, ddgVector3 *n, ddgColor3 *c)
{
	// Steep normal
    if (fabs(n->v[1]) < _cliffangle)
		c->set(_cliff); // Cliff
    else if (p->v[1] < _beachalt)
		c->set(_beach); // Beach
    else if (p->v[1] < _grassalt)
		c->set(_grass); // Grass
    else if (p->v[1] < _treealt)
		c->set(_trees); // Trees
    else if (p->v[1] < _rockalt)
		c->set(_rock);  // Rock
    else
		c->set(_snow);  // Snow

	static int cl = 0, b=0,g=0,t=0,r=0,s=0;
    if (fabs(n->v[1]) < _cliffangle)
		cl++;
    else if (p->v[1] < _beachalt)
		b++;
    else if (p->v[1] < _grassalt)
		g++;
    else if (p->v[1] < _treealt)
		t++;
    else if (p->v[1] < _rockalt)
		r++;
    else
		s++;
}

static csRenderView *grview = NULL;
// Perform coord transformation using CS instead of DDG.
static void transformer(ddgVector3 vin, ddgVector3 *vout)
{
	if (grview)
	{
		csVector3 csw1 = grview->World2Camera( csVector3(vin.v[0],vin.v[1],vin.v[2]) );
		vout->v[0] = csw1.x;
		vout->v[1] = csw1.y;
		vout->v[2] = csw1.z;
	}
	else
	{
		vout->v[0] = vin.v[0];
		vout->v[1] = vin.v[1];
		vout->v[2] = vin.v[2];
	}
}

// Z depth queue iterator
static ddgSplayIterator		*qri;
// Z depth queue.
static ddgQueue			*qr;

bool csTerrain::Initialize (char* heightmap)
{

  CHK (height = new ddgHeightMap ());
  if (height->readTGN (heightmap))
	  height->generateHeights(257,257,5);
  CHK (mesh = new ddgTBinMesh (height));
  CHK (clipbox = new ddgBBox (ddgVector3(0,0,1),ddgVector3(640, 480, 15000)));

  float fov = 90.0;
  mesh->settransform(transformer);
  mesh->init (NULL, clipbox, fov);

	_cliff.set(175,175,175);  // Cliff
	_beach.set(200,200,50);  // Beach.
	_grass.set(95,145,70);    // Grass
	_trees.set(25,50,25);     // Trees
	_rock.set(125,125,125);      // Rock
	_snow.set(250,250,250);      // Snow

	_cliffangle = 0.2; // up component of normal vector.
	_beachalt = 0;
	_grassalt = 3;
	_treealt = 5;
	_rockalt = 7;
	_snowalt = 999;

  return true;
}

void csTerrain::Draw (csRenderView& rview, bool /*use_z_buf*/)
{
  G3DPolygonDPFX poly;

  memset (&poly, 0, sizeof(poly));
  poly.inv_aspect = rview.inv_aspect;
  poly.flat_color_r = 1;
  poly.flat_color_g = 1;
  poly.flat_color_b = 1;
  poly.txt_handle = _textureMap->GetTextureHandle ();
  rview.g3d->SetRenderState (G3DRENDERSTATE_ZBUFFERTESTENABLE, false /*use_z_buf*/);
  rview.g3d->SetRenderState (G3DRENDERSTATE_ZBUFFERFILLENABLE, true);
  rview.g3d->StartPolygonFX (poly.txt_handle, CS_FX_GOURAUD);
  grview = &rview;
  // For each frame.
  mesh->calculate ();

	// If we are not using Z-buffer...
    // For all the triangle in the visible queue, insert them in z-order.

  	if ( 1 /*!use_z_buf*/ )
	{
		mesh->qzi()->reset();
		// Clear queue.
		mesh->qz()->clear();
		mesh->qsi()->reset();
		while (!mesh->qsi()->end())
		{
			ddgTriIndex tvc = mesh->qs ()->index (mesh->qsi ()), tvp, tv0, tv1;
            float d;
			ddgTBinTree *bt = mesh->qs ()->tree (mesh->qsi ());

            tvp = ddgTBinTree::parent(tvc);
            tv0 = mesh->stri[tvc].v0;
            tv1 = mesh->stri[tvc].v1;
			ddgVector3 *p = bt->tri(tv0)->pos();
    		// Use the nearest coord of the triangle.
            d = p->v[2];
			p = bt->tri(tv1)->pos();
            if (p->v[2] < d)
                d = p->v[2];
			p = bt->tri(tvp)->pos();
            if (p->v[2] < d)
                d = p->v[2];
            mesh->qz()->ddgSplayTree::insert (bt->index(),tvc,(unsigned int)d);
			mesh->qsi ()->next ();
		}
		qri = mesh->qzi();
		qr  = mesh->qz();
	}
	else
	{
		qri = mesh->qsi ();
		qr  = mesh->qs ();
	}

   // Render
  qri->reset ();
  while (!qri->end ())
  {
    ddgTriIndex tvc = qr->index (qri );
    ddgTBinTree *bt = qr->tree (qri );

    if (!bt->tri (tvc)->vis ().flags.none)
    {

      ddgVector3 *p1, *p2, *p3;
      ddgVector3 wp1, wp2, wp3;
      ddgVector3 n1, n2, n3;
      ddgVector2 t1, t2, t3;
      ddgColor3  c1, c2, c3;
	  unsigned int tvp = bt->parent (tvc),
		  tv0 = bt->v0 (tvc),
		  tv1 = bt->v1 (tvc);
	  // Camera space coords.
	  p3 =	bt->tri(tvp)->pos();
	  p2 =	bt->tri(tv0)->pos();
	  p1 =	bt->tri(tv1)->pos();
	  // World space coords.
      bt->vertex(tvp,&wp1);
      bt->vertex(tv0,&wp2);
      bt->vertex(tv1,&wp3);
	  // Normals.
	  bt->normal(tvp,&n1);
	  bt->normal(tv0,&n2);
	  bt->normal(tv1,&n3);
      // Texture coords from 0 - N where N is size of texture.
	  bt->textureC(tvp,t1);
	  bt->textureC(tv0,t2);
	  bt->textureC(tv1,t3);
	  // Create some color scheme.
	  classify(wp1,&n1,&c1);
	  classify(wp2,&n2,&c2);
	  classify(wp3,&n3,&c3);

      float iz;
      float pz[3];
      csVector2 triangle[3];
      if (p1->v[2] < SMALL_Z) goto not_vis;
      pz[0] = 1 / p1->v[2];
      iz = rview.aspect * pz[0];
      triangle[0].x = p1->v[0] * iz + rview.shift_x;
      triangle[0].y = p1->v[1] * iz + rview.shift_x;
      if (p2->v[2] < SMALL_Z) goto not_vis;
      pz[1] = 1 / p2->v[2];
      iz = rview.aspect * pz[1];
      triangle[1].x = p2->v[0] * iz + rview.shift_x;
      triangle[1].y = p2->v[1] * iz + rview.shift_x;
      if (p3->v[2] < SMALL_Z) goto not_vis;
      pz[2] = 1 / p3->v[2];
      iz = rview.aspect * pz[2];
      triangle[2].x = p3->v[0] * iz + rview.shift_x;
      triangle[2].y = p3->v[1] * iz + rview.shift_x;

      csVector2 clipped_triangle [10];	//@@@BAD HARCODED!
      int rescount;
      if (!rview.view->Clip (triangle, clipped_triangle, 3, rescount)) goto not_vis;
      poly.num = rescount;

      poly.vertices[0].z = pz[0];
      poly.vertices[0].u = 0;
      poly.vertices[0].v = 0;
      poly.vertices[0].r = (float)c1.v[0]/255.0;
      poly.vertices[0].g = (float)c1.v[1]/255.0;
      poly.vertices[0].b = (float)c1.v[2]/255.0;

      poly.vertices[1].z = pz[1];
      poly.vertices[1].u = 1;
      poly.vertices[1].v = 0;
      poly.vertices[1].r = (float)c2.v[0]/255.0;
      poly.vertices[1].g = (float)c2.v[1]/255.0;
      poly.vertices[1].b = (float)c2.v[2]/255.0;

      poly.vertices[2].z = pz[2];
      poly.vertices[2].u = 0;
      poly.vertices[2].v = 1;
      poly.vertices[2].r = (float)c3.v[0]/255.0;
      poly.vertices[2].g = (float)c3.v[1]/255.0;
      poly.vertices[2].b = (float)c3.v[2]/255.0;

      PreparePolygonFX (&poly, clipped_triangle, rescount, triangle,
      	true);
      rview.g3d->DrawPolygonFX (poly);
    }

    not_vis:
    qri ->next ();
  }

  rview.g3d->FinishPolygonFX ();
}

<|endoftext|>


<commit_before>/**
 * @file   Equation.hpp
 * @brief  Equation.
 * @author zer0
 * @date   2016-08-26
 */

#ifndef __INCLUDE_LIBTBAG__LIBTBAG_MATH_EQUATION_HPP__
#define __INCLUDE_LIBTBAG__LIBTBAG_MATH_EQUATION_HPP__

// MS compatible compilers support #pragma once
#if defined(_MSC_VER) && (_MSC_VER >= 1020)
#pragma once
#endif

#include <libtbag/config.h>
#include <libtbag/predef.hpp>
#include <libtbag/geometry/Point.hpp>

#include <cassert>
#include <algorithm>
#include <limits>

// -------------------
NAMESPACE_LIBTBAG_OPEN
// -------------------

namespace math {

/**
 * Linear Equation.
 *
 * @translate{ko, 일차 방정식.}
 *
 * @author zer0
 * @date   2016-08-26
 *
 * @remarks
 *  \f[
 *   y = ax + b
 *  \f]
 *  - a: Gradient (기울기).
 *  - b: Y-intercept (Y절편).
 *
 * @warning
 *  Impossible equation: \f$ x = b \f$
 */
template <typename T>
struct LinearEquation
{
    T a; ///< Gradient.
    T b; ///< Y-intercept.
};

template <typename T>
inline T getY(LinearEquation<T> e, T x)
{
    return e.a * x + e.b;
}

/**
 * Quadratic Equation.
 *
 * @translate{ko, 이차 방정식.}
 *
 * @author zer0
 * @date   2016-08-26
 *
 * @remarks
 *  \f[
 *   y = ax^{2} + bx + c
 *  \f]
 */
template <typename T>
struct QuadraticEquation
{
    T a, b, c;
};

/**
 * Obtain the linear-equation.
 *
 * @param x1 [in] Point 1, x.
 * @param y1 [in] Point 1, y.
 * @param x2 [in] Point 2, x.
 * @param y2 [in] Point 2, y.
 *
 * @remarks
 *  \f[
 *   \begin{align}
 *   y &= ax + b \\
 *     &= (\frac{y_2 - y_1}{x_2 - x_1}) (x - x_1) + y_1 \\
 *     &= (\frac{y_2 - y_1}{x_2 - x_1})x - (\frac{y_2 - y_1}{x_2 - x_1})x_1 + y_1 \\
 *   \end{align}
 *   \\
 *   RESULT: a = \frac{y_2 - y_1}{x_2 - x_1}, b = -ax_1 + y_1, (x_1 \neq x_2)
 *  \f]
 */
template <typename T>
inline LinearEquation<T>
getLinearEquationWithTwoPoint(T x1, T y1, T x2, T y2)
{
    assert(x1 != x2);
    LinearEquation<T> result;
    result.a = (y2 - y1) / (x2 - x1);
    result.b = result.a * (-1) * x1 + y1;
    return result;
}

/**
 * Obtain the linear-equation.
 *
 * @translate{ko, 두 점을 사용하여 일차 방정식을 구한다.}
 *
 * @param p1 [in] Point 1.
 * @param p2 [in] Point 2.
 */
template <typename T, typename PointType = geometry::BasePoint<T> >
inline LinearEquation<T>
getLinearEquationWithTwoPoint(PointType const & p1, PointType const & p2)
{
    return getLinearEquationWithTwoPoint(p1.x, p1.y, p2.x, p2.y);
}

/**
 * Check the two equations are parallel.
 *
 * @translate{ko, 두 직선이 평행한지 확인한다.}
 */
template <typename T>
inline bool
isParallelWithTwoLinearEquation(LinearEquation<T> const & e1, LinearEquation<T> const & e2)
{
    return e1.a == e2.a;
}

/**
 * Check the two equations are perpendicular.
 *
 * @translate{ko, 두 직선이 수직한지 확인한다.}
 */
template <typename T>
inline bool
isPerpendicularWithTwoLinearEquation(LinearEquation<T> const & e1, LinearEquation<T> const & e2)
{
    return e1.a * e2.b == -1;
}

/**
 * Calculate the intersection of two equations(lines).
 *
 * @translate{ko, 두 직선의 교차점을 구한다.}
 *
 * @remarks
 *  Two linear equation:
 *  \f[
 *   y = a_1x + b_1 \\
 *   y = a_2x + b_2 \\
 *  \f]
 *  Explanation:
 *  \f[
 *   \begin{align}
 *     a_1x + b_1   &= a_2x + b_2 \\
 *     a_1x - a_2x  &= b_2 - b_1 \\
 *    (a_1  - a_2)x &= b_2 - b_1 \\
 *                x &= \frac{b_2 - b_1}{a_1 - a_2} \\
 *   \end{align}
 *   \\
 *   RESULT: x = \frac{b_2 - b_1}{a_1 - a_2}, y = a_1x + b_1, (a_1 \neq a_2)
 *  \f]
 */
template <typename T, typename PointType = geometry::BasePoint<T> >
inline PointType getIntersectionWithTwoLinearEquation(LinearEquation<T> const & e1, LinearEquation<T> const & e2)
{
    assert(e1.a != e2.a);
    PointType result;
    result.x = (e2.b - e1.b) / (e1.a - e2.a);
    result.y = e1.a * result.x + e1.b;
    return result;
}

/**
 * Check if it is included in the range.
 */
template <typename T>
inline bool isContains(T const & p1, T const & p2, T const & check)
{
    T const MIN = std::min(p1, p2);
    T const MAX = std::max(p1, p2);
    return (MIN <= COMPARE_AND(check) <= MAX);
}

/**
 * Check if it is included in the range.
 */
template <typename T, typename PointType = geometry::BasePoint<T> >
inline bool isContains2d(PointType const & p1, PointType const & p2, PointType const & check)
{
    T const X_MIN = std::min(p1.x, p2.x);
    T const X_MAX = std::max(p1.x, p2.x);
    T const Y_MIN = std::min(p1.y, p2.y);
    T const Y_MAX = std::max(p1.y, p2.y);
    return (X_MIN <= COMPARE_AND(check.x) <= X_MAX &&
            Y_MIN <= COMPARE_AND(check.y) <= Y_MAX);
}

/**
 *
 * @remarks
 *  Equations of the form x = a are impossible. @n
 *  These equations are calculated separately.
 */
template <typename T, typename PointType = geometry::BasePoint<T> >
bool isCross(PointType const & p11, PointType const & p12, PointType const & p21, PointType const & p22, PointType & cross)
{
    bool const SAME_P1_X = (p11.x == p12.x);
    bool const SAME_P2_X = (p21.x == p22.x);

    if (SAME_P1_X == false && SAME_P2_X == false) {
        LinearEquation<T> e1 = getLinearEquationWithTwoPoint<T, PointType>(p11, p12);
        LinearEquation<T> e2 = getLinearEquationWithTwoPoint<T, PointType>(p21, p22);

        if (isParallelWithTwoLinearEquation<T>(e1, e2)) {
            return false;
        }
        cross = getIntersectionWithTwoLinearEquation<T, PointType>(e1, e2);
        if (p21.y == p22.y) {
            cross.y = p22.y;
        }
        return isContains2d<T, PointType>(p11, p12, cross) && isContains2d<T, PointType>(p21, p22, cross);

    } else if (SAME_P1_X == false && SAME_P2_X) {
        // p21->p22 is a horizontal straight line.
        LinearEquation<T> e1 = getLinearEquationWithTwoPoint<T, PointType>(p11, p12);
        cross = PointType(p21.x, getY<T>(e1, p21.x));
        return isContains<T>(p21.y, p22.y, cross.y) && isContains2d<T, PointType>(p11, p12, cross);

    } else if (SAME_P1_X && SAME_P2_X == false) {
        // p11->p12 is a horizontal straight line.
        LinearEquation<T> e2 = getLinearEquationWithTwoPoint<T, PointType>(p21, p22);
        cross = PointType(p11.x, getY<T>(e2, p11.x));
        return isContains<T>(p11.y, p12.y, cross.y) && isContains2d<T, PointType>(p21, p22, cross);
    }

    // p11->p12 & p21->p22 is a horizontal straight line.
    assert(SAME_P1_X && SAME_P2_X);
    return false;
}

} // namespace math

// --------------------
NAMESPACE_LIBTBAG_CLOSE
// --------------------

#endif // __INCLUDE_LIBTBAG__LIBTBAG_MATH_EQUATION_HPP__

<commit_msg>Rename: isContains2d() -> isAlmostContains2d()<commit_after>/**
 * @file   Equation.hpp
 * @brief  Equation.
 * @author zer0
 * @date   2016-08-26
 */

#ifndef __INCLUDE_LIBTBAG__LIBTBAG_MATH_EQUATION_HPP__
#define __INCLUDE_LIBTBAG__LIBTBAG_MATH_EQUATION_HPP__

// MS compatible compilers support #pragma once
#if defined(_MSC_VER) && (_MSC_VER >= 1020)
#pragma once
#endif

#include <libtbag/config.h>
#include <libtbag/predef.hpp>
#include <libtbag/algorithm/Equals.hpp>
#include <libtbag/geometry/Point.hpp>

#include <cassert>
#include <algorithm>
#include <limits>

// -------------------
NAMESPACE_LIBTBAG_OPEN
// -------------------

namespace math {

/**
 * Linear Equation.
 *
 * @translate{ko, 일차 방정식.}
 *
 * @author zer0
 * @date   2016-08-26
 *
 * @remarks
 *  \f[
 *   y = ax + b
 *  \f]
 *  - a: Gradient (기울기).
 *  - b: Y-intercept (Y절편).
 *
 * @warning
 *  Impossible equation: \f$ x = b \f$
 */
template <typename T>
struct LinearEquation
{
    T a; ///< Gradient.
    T b; ///< Y-intercept.
};

template <typename T>
inline T getY(LinearEquation<T> e, T x)
{
    return e.a * x + e.b;
}

/**
 * Quadratic Equation.
 *
 * @translate{ko, 이차 방정식.}
 *
 * @author zer0
 * @date   2016-08-26
 *
 * @remarks
 *  \f[
 *   y = ax^{2} + bx + c
 *  \f]
 */
template <typename T>
struct QuadraticEquation
{
    T a, b, c;
};

/**
 * Obtain the linear-equation.
 *
 * @param x1 [in] Point 1, x.
 * @param y1 [in] Point 1, y.
 * @param x2 [in] Point 2, x.
 * @param y2 [in] Point 2, y.
 *
 * @remarks
 *  \f[
 *   \begin{align}
 *   y &= ax + b \\
 *     &= (\frac{y_2 - y_1}{x_2 - x_1}) (x - x_1) + y_1 \\
 *     &= (\frac{y_2 - y_1}{x_2 - x_1})x - (\frac{y_2 - y_1}{x_2 - x_1})x_1 + y_1 \\
 *   \end{align}
 *   \\
 *   RESULT: a = \frac{y_2 - y_1}{x_2 - x_1}, b = -ax_1 + y_1, (x_1 \neq x_2)
 *  \f]
 */
template <typename T>
inline LinearEquation<T>
getLinearEquationWithTwoPoint(T x1, T y1, T x2, T y2)
{
    assert(x1 != x2);
    LinearEquation<T> result;
    result.a = (y2 - y1) / (x2 - x1);
    result.b = result.a * (-1) * x1 + y1;
    return result;
}

/**
 * Obtain the linear-equation.
 *
 * @translate{ko, 두 점을 사용하여 일차 방정식을 구한다.}
 *
 * @param p1 [in] Point 1.
 * @param p2 [in] Point 2.
 */
template <typename T, typename PointType = geometry::BasePoint<T> >
inline LinearEquation<T>
getLinearEquationWithTwoPoint(PointType const & p1, PointType const & p2)
{
    return getLinearEquationWithTwoPoint(p1.x, p1.y, p2.x, p2.y);
}

/**
 * Check the two equations are parallel.
 *
 * @translate{ko, 두 직선이 평행한지 확인한다.}
 */
template <typename T>
inline bool
isParallelWithTwoLinearEquation(LinearEquation<T> const & e1, LinearEquation<T> const & e2)
{
    return algorithm::equals<T>(e1.a, e2.a);
}

/**
 * Check the two equations are perpendicular.
 *
 * @translate{ko, 두 직선이 수직한지 확인한다.}
 */
template <typename T>
inline bool
isPerpendicularWithTwoLinearEquation(LinearEquation<T> const & e1, LinearEquation<T> const & e2)
{
    return algorithm::equals<T>(e1.a * e2.b, static_cast<T>(-1));
}

/**
 * Calculate the intersection of two equations(lines).
 *
 * @translate{ko, 두 직선의 교차점을 구한다.}
 *
 * @remarks
 *  Two linear equation:
 *  \f[
 *   y = a_1x + b_1 \\
 *   y = a_2x + b_2 \\
 *  \f]
 *  Explanation:
 *  \f[
 *   \begin{align}
 *     a_1x + b_1   &= a_2x + b_2 \\
 *     a_1x - a_2x  &= b_2 - b_1 \\
 *    (a_1  - a_2)x &= b_2 - b_1 \\
 *                x &= \frac{b_2 - b_1}{a_1 - a_2} \\
 *   \end{align}
 *   \\
 *   RESULT: x = \frac{b_2 - b_1}{a_1 - a_2}, y = a_1x + b_1, (a_1 \neq a_2)
 *  \f]
 */
template <typename T, typename PointType = geometry::BasePoint<T> >
inline PointType getIntersectionWithTwoLinearEquation(LinearEquation<T> const & e1, LinearEquation<T> const & e2)
{
    assert(e1.a != e2.a);
    PointType result;
    result.x = (e2.b - e1.b) / (e1.a - e2.a);
    result.y = e1.a * result.x + e1.b;
    return result;
}

/**
 * Check if it is included in the range.
 */
template <typename T>
inline bool isAlmostContains(T const & v1, T const & v2, T const & check) TBAG_NOEXCEPT
{
    T const MIN = std::min(v1, v2);
    T const MAX = std::max(v1, v2);
    using namespace algorithm;
    return lessOrEquals(MIN, check) && greaterOrEquals(MAX, check);
}

/**
 * Check if it is included in the range.
 */
template <typename T, typename PointType = geometry::BasePoint<T> >
inline bool isAlmostContains2d(PointType const & p1, PointType const & p2, PointType const & check) TBAG_NOEXCEPT
{
    return isAlmostContains(p1.x, p2.x, check.x) && isAlmostContains(p1.y, p2.y, check.y);
}

/**
 *
 * @remarks
 *  Equations of the form x = a are impossible. @n
 *  These equations are calculated separately.
 */
template <typename T, typename PointType = geometry::BasePoint<T> >
bool isCross(PointType const & p11, PointType const & p12, PointType const & p21, PointType const & p22, PointType & cross)
{
    bool const SAME_P1_X = (p11.x == p12.x);
    bool const SAME_P2_X = (p21.x == p22.x);

    if (SAME_P1_X == false && SAME_P2_X == false) {
        LinearEquation<T> e1 = getLinearEquationWithTwoPoint<T, PointType>(p11, p12);
        LinearEquation<T> e2 = getLinearEquationWithTwoPoint<T, PointType>(p21, p22);

        if (isParallelWithTwoLinearEquation<T>(e1, e2)) {
            return false;
        }
        cross = getIntersectionWithTwoLinearEquation<T, PointType>(e1, e2);
        return isAlmostContains2d<T, PointType>(p11, p12, cross) && isAlmostContains2d<T, PointType>(p21, p22, cross);

    } else if (SAME_P1_X == false && SAME_P2_X) {
        // p21->p22 is a horizontal straight line.
        LinearEquation<T> e1 = getLinearEquationWithTwoPoint<T, PointType>(p11, p12);
        cross = PointType(p21.x, getY<T>(e1, p21.x));
        return isAlmostContains<T>(p21.y, p22.y, cross.y) && isAlmostContains2d<T, PointType>(p11, p12, cross);

    } else if (SAME_P1_X && SAME_P2_X == false) {
        // p11->p12 is a horizontal straight line.
        LinearEquation<T> e2 = getLinearEquationWithTwoPoint<T, PointType>(p21, p22);
        cross = PointType(p11.x, getY<T>(e2, p11.x));
        return isAlmostContains<T>(p11.y, p12.y, cross.y) && isAlmostContains2d<T, PointType>(p21, p22, cross);
    }

    // p11->p12 & p21->p22 is a horizontal straight line.
    assert(SAME_P1_X && SAME_P2_X);
    return false;
}

} // namespace math

// --------------------
NAMESPACE_LIBTBAG_CLOSE
// --------------------

#endif // __INCLUDE_LIBTBAG__LIBTBAG_MATH_EQUATION_HPP__

<|endoftext|>