<commit_before>// FONgGrid.cc

// This file is part of BES GDAL File Out Module

// Copyright (c) 2012 OPeNDAP, Inc.
// Author: James Gallagher <jgallagher@opendap.org>
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; either
// version 2.1 of the License, or (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
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
//
// You can contact University Corporation for Atmospheric Research at
// 3080 Center Green Drive, Boulder, CO 80301

#include <BESInternalError.h>
#include <BESDebug.h>

#include <gdal.h>
#include <gdal_priv.h>
#include <ogr_spatialref.h>

#include <DDS.h>
#include <Grid.h>
// #include <ce_functions.h>
#include <util.h>

#include "GeoTiffTransmitter.h"
#include "FONgTransform.h"
#include "FONgBaseType.h"
#include "FONgGrid.h"

using namespace libdap;

/** @brief Constructor for FONgGrid that takes a DAP Grid
 *
 * @param g A DAP BaseType that should be a grid
 */
FONgGrid::FONgGrid(Grid *g) : FONgBaseType(), d_grid(g), d_lat(0), d_lon(0)
{
    d_type = dods_grid_c;

    // Build sets of attribute values for easy searching.
    // Copied from GeoConstriant in libdap. That class is
    // abstract and didn't want to modify libdap's ABI for this hack.

    d_coards_lat_units.insert("degrees_north");
    d_coards_lat_units.insert("degree_north");
    d_coards_lat_units.insert("degree_N");
    d_coards_lat_units.insert("degrees_N");

    d_coards_lon_units.insert("degrees_east");
    d_coards_lon_units.insert("degree_east");
    d_coards_lon_units.insert("degrees_E");
    d_coards_lon_units.insert("degree_E");

    d_lat_names.insert("COADSY");
    d_lat_names.insert("lat");
    d_lat_names.insert("Lat");
    d_lat_names.insert("LAT");

    d_lon_names.insert("COADSX");
    d_lon_names.insert("lon");
    d_lon_names.insert("Lon");
    d_lon_names.insert("LON");
}

/** @brief Destructor that cleans up the grid
 *
 * The DAP Grid instance does not belong to the FONgGrid instance, so it
 * is not deleted.
 */
FONgGrid::~FONgGrid()
{
}

/** This is used with find_if(). The GeoConstraint class holds a set of strings
    which are prefixes for variable names. Using the regular find() locates
    only the exact matches, using find_if() with this functor makes is easy
    to treat those set<string> objects as collections of prefixes. */
class is_prefix
{
private:
    string s;
public:
    is_prefix(const string & in): s(in)
    {}

    bool operator()(const string & prefix)
    {
        return s.find(prefix) == 0;
    }
};

/** Is this a latitude map? Use CF's long_name attribute first, then
 * drop into heuristics based on units names or common variable names.
 *
 * @param var_units The value of the 'unit' attribute
 * @param var_name The name of the variable
 * @param long_name The value of the long_name attribute
 *
 * @return true if there's a match, otherwise false
 * @see m_lon_unit_or_name_match()
 */
bool
FONgGrid::m_lat_unit_or_name_match(const string &var_units, const string &var_name,
                                   const string &long_name)
{
    return (long_name == "latitude"
            || d_coards_lat_units.find(var_units) != d_coards_lat_units.end()
            || find_if(d_lat_names.begin(), d_lat_names.end(), is_prefix(var_name)) != d_lat_names.end());
}

bool
FONgGrid::m_lon_unit_or_name_match(const string &var_units, const string &var_name,
                                   const string &long_name)
{
    return (long_name == "longitude"
            || d_coards_lon_units.find(var_units) != d_coards_lon_units.end()
            || find_if(d_lon_names.begin(), d_lon_names.end(), is_prefix(var_name)) != d_lon_names.end());
}

/** A private method called by the constructor that searches for latitude
    and longitude map vectors. This method returns false if either map
    cannot be found. It assumes that the d_grid and d_dds fields are set.

    The d_longitude, d_lon, d_lon_length and d_lon_grid_dim (and matching
    lat) fields are modified.

    @note Rules used to find Maps:

Latitude: If the Map has a units attribute of "degrees_north",
    "degree_north", "degree_N", or "degrees_N"

Longitude: If the map has a units attribute of "degrees_east"
    (eastward positive), "degree_east", "degree_E", or "degrees_E"

    @return True if the maps are found, otherwise False */
bool FONgGrid::find_lat_lon_maps()
{
    Grid::Map_iter m = d_grid->map_begin();

    // Assume that a Grid is correct and thus has exactly as many maps as its
    // array part has dimensions. Thus, don't bother to test the Grid's array
    // dimension iterator for '!= dim_end()'.
    Array::Dim_iter d = d_grid->get_array()->dim_begin();

    // The fields d_latitude and d_longitude may be initialized to null or they
    // may already contain pointers to the maps to use. In the latter case,
    // skip the heuristics used in this code. However, given that all this
    // method does is find the lat/lon maps, if they are given in the ctor,
    // This method will likely not be called at all.

    while (m != d_grid->map_end() && (!d_lat || !d_lon)) {
        string units_value = (*m)->get_attr_table().get_attr("units");
        units_value = remove_quotes(units_value);
        string long_name = (*m)->get_attr_table().get_attr("long_name");
        long_name = remove_quotes(long_name);
        string map_name = (*m)->name();

        // The 'units' attribute must match exactly; the name only needs to
        // match a prefix.
        if (!d_lat && m_lat_unit_or_name_match(units_value, map_name, long_name)) {
            // Set both d_latitude (a pointer to the real map vector) and
            // d_lat, a vector of the values represented as doubles. It's easier
            // to work with d_lat, but it's d_latitude that needs to be set
            // when constraining the grid. Also, record the grid variable's
            // dimension iterator so that it's easier to set the Grid's Array
            // (which also has to be constrained).
            d_lat = dynamic_cast < Array * >(*m);
            if (!d_lat)
                throw InternalErr(__FILE__, __LINE__, "Expected an array.");

            if (!d_lat->read_p())
                d_lat->read();
        }

        if (!d_lon && m_lon_unit_or_name_match(units_value, map_name, long_name)) {
            d_lon = dynamic_cast < Array * >(*m);
            if (!d_lon)
                throw InternalErr(__FILE__, __LINE__, "Expected an array.");

            if (!d_lon->read_p())
                d_lon->read();
        }

        ++m;
        ++d;
    }

    return d_lat && d_lon;
}

/** Extract the size (pixels), element data type and top-left and
 * bottom-right lat/lon corner points for the Grid. Also determine
 * if this is a 2D or 3D Grid and, in the latter case, ensure that
 * the first dimension is not lat or lon. In that case, the geotiff
 * will have N bands, where N is the number of elements from the
 * first dimension in the current selection.
 *
 */
void FONgGrid::extract_coordinates(FONgTransform &t)
{
    BESDEBUG("fong3", "Entering FONgGrid::extract_coordinates" << endl);

    double *lat = 0, *lon = 0;
    try {
        // Find the lat and lon maps for this Grid; throws Error
        // if the are not found.
        find_lat_lon_maps();

        // The array size
        t.set_height(d_lat->length());
        t.set_width(d_lon->length());

        lat = extract_double_array(d_lat);
        lon = extract_double_array(d_lon);

        t.set_top(lat[0]);
        t.set_left(lon[0]);
        t.set_bottom(lat[t.height() - 1]);
        t.set_right(lon[t.width() -1]);

        // Read this from the 'missing_value' or '_FillValue' attributes
        string missing_value = d_grid->get_attr_table().get_attr("missing_value");
        if (missing_value.empty())
            missing_value = d_grid->get_array()->get_attr_table().get_attr("missing_value");
        if (missing_value.empty())
            missing_value = d_grid->get_attr_table().get_attr("_FillValue");
        if (missing_value.empty())
            missing_value = d_grid->get_array()->get_attr_table().get_attr("_FillValue");

        BESDEBUG("fong3", "missing_value attribute: " << missing_value << endl);

        // NB: no_data_type() is 'none' by default
        if (!missing_value.empty()) {
            t.set_no_data(missing_value);
            if (t.no_data() < 0)
                t.set_no_data_type(FONgTransform::negative);
            else
                t.set_no_data_type(FONgTransform::positive);
        }

        t.geo_transform_set(true);

        t.set_num_bands(t.num_bands() + 1);
        t.push_var(this);

        delete[] lat;
        delete[] lon;
    }
    catch (Error &e) {
        delete[] lat;
        delete[] lon;

        throw;
    }
}

/** Use CF to determine if this is a 'Spherical Earth' datum */
static bool is_spherical(BaseType *btp)
{
    /* crs:grid_mapping_name = "latitude_longitude"
    crs:semi_major_axis = 6371000.0 ;
    crs:inverse_flattening = 0 ; */

    bool gmn = btp->get_attr_table().get_attr("grid_mapping_name") == "latitude_longitude";
    bool sma = btp->get_attr_table().get_attr("semi_major_axis") == "6371000.0";
    bool iflat = btp->get_attr_table().get_attr("inverse_flattening") == "0";

    return gmn && sma && iflat;
}

/** Use CF to determine if this is a 'WGS84' datum */
static bool is_wgs84(BaseType *btp)
{
    /*crs:grid_mapping_name = "latitude_longitude";
    crs:longitude_of_prime_meridian = 0.0 ;
    crs:semi_major_axis = 6378137.0 ;
    crs:inverse_flattening = 298.257223563 ; */

    bool gmn = btp->get_attr_table().get_attr("grid_mapping_name") == "latitude_longitude";
    bool lpm = btp->get_attr_table().get_attr("longitude_of_prime_meridian") == "0.0";
    bool sma = btp->get_attr_table().get_attr("semi_major_axis") == "6378137.0";
    bool iflat = btp->get_attr_table().get_attr("inverse_flattening") == "298.257223563";

    return gmn && lpm && sma && iflat;
}

/** @brief Set the projection information
 * For Grids, look for CF information. If it's not present, use the
 * default Geographic Coordinate system set in the bes/module conf
 * file. if it is present, look at the attributes and dope out a Well
 * Known Geographic coordinate string.
 */
string FONgGrid::get_projection(DDS *dds)
{
    // Here's the information about the CF and projections
    // http://cf-pcmdi.llnl.gov/documents/cf-conventions/1.4/cf-conventions.html#grid-mappings-and-projections
    // How this code looks for mapping information: Look for an
    // attribute named 'grid_mapping' and get it's value. This attribute
    // with be the name of a variable in the dataset, so get that
    // variable. Now, look at the attributes of that variable.
    string mapping_info = d_grid->get_attr_table().get_attr("grid_mapping");
    if (mapping_info.empty())
        mapping_info = d_grid->get_array()->get_attr_table().get_attr("grid_mapping");

    string WK_GCS = GeoTiffTransmitter::default_gcs;

    if (!mapping_info.empty()) {
        // "WGS84": same as "EPSG:4326" but has no dependence on EPSG data files.
        // "WGS72": same as "EPSG:4322" but has no dependence on EPSG data files.
        // "NAD27": same as "EPSG:4267" but has no dependence on EPSG data files.
        // "NAD83": same as "EPSG:4269" but has no dependence on EPSG data files.
        // "EPSG:n": same as doing an ImportFromEPSG(n).

        // The mapping info is actually stored as attributes of an Int32 variable.
        BaseType *btp = dds->var(mapping_info);
        if (btp->name() == "crs") {
            if (is_wgs84(btp))
                WK_GCS = "WGS84";
            else if (is_spherical(btp))
                WK_GCS = "EPSG:4047";
        }
    }

    OGRSpatialReference srs;
    srs.SetWellKnownGeogCS(WK_GCS.c_str());
    char *srs_wkt = NULL;
    srs.exportToWkt(&srs_wkt);

    string wkt = srs_wkt;   // save the result

    CPLFree(srs_wkt);       // free memory alloc'd by GDAL

    return wkt;
}

double *FONgGrid::get_data()
{
    if (!d_grid->get_array()->read_p())
        d_grid->get_array()->read();

    // This code assumes read() has been called.
    return extract_double_array(d_grid->get_array());
}

<commit_msg>Added an include of <algorithm> for an issue that shows up on gcc 4.4<commit_after>// FONgGrid.cc

// This file is part of BES GDAL File Out Module

// Copyright (c) 2012 OPeNDAP, Inc.
// Author: James Gallagher <jgallagher@opendap.org>
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; either
// version 2.1 of the License, or (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
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
//
// You can contact University Corporation for Atmospheric Research at
// 3080 Center Green Drive, Boulder, CO 80301

#include <algorithm>

#include <gdal.h>
#include <gdal_priv.h>
#include <ogr_spatialref.h>

#include <DDS.h>
#include <Grid.h>
// #include <ce_functions.h>
#include <util.h>

#include <BESInternalError.h>
#include <BESDebug.h>

#include "GeoTiffTransmitter.h"
#include "FONgTransform.h"
#include "FONgBaseType.h"
#include "FONgGrid.h"

using namespace libdap;

/** @brief Constructor for FONgGrid that takes a DAP Grid
 *
 * @param g A DAP BaseType that should be a grid
 */
FONgGrid::FONgGrid(Grid *g) : FONgBaseType(), d_grid(g), d_lat(0), d_lon(0)
{
    d_type = dods_grid_c;

    // Build sets of attribute values for easy searching.
    // Copied from GeoConstriant in libdap. That class is
    // abstract and didn't want to modify libdap's ABI for this hack.

    d_coards_lat_units.insert("degrees_north");
    d_coards_lat_units.insert("degree_north");
    d_coards_lat_units.insert("degree_N");
    d_coards_lat_units.insert("degrees_N");

    d_coards_lon_units.insert("degrees_east");
    d_coards_lon_units.insert("degree_east");
    d_coards_lon_units.insert("degrees_E");
    d_coards_lon_units.insert("degree_E");

    d_lat_names.insert("COADSY");
    d_lat_names.insert("lat");
    d_lat_names.insert("Lat");
    d_lat_names.insert("LAT");

    d_lon_names.insert("COADSX");
    d_lon_names.insert("lon");
    d_lon_names.insert("Lon");
    d_lon_names.insert("LON");
}

/** @brief Destructor that cleans up the grid
 *
 * The DAP Grid instance does not belong to the FONgGrid instance, so it
 * is not deleted.
 */
FONgGrid::~FONgGrid()
{
}

/** This is used with find_if(). The GeoConstraint class holds a set of strings
    which are prefixes for variable names. Using the regular find() locates
    only the exact matches, using find_if() with this functor makes is easy
    to treat those set<string> objects as collections of prefixes. */
class is_prefix
{
private:
    string s;
public:
    is_prefix(const string & in): s(in)
    {}

    bool operator()(const string & prefix)
    {
        return s.find(prefix) == 0;
    }
};

/** Is this a latitude map? Use CF's long_name attribute first, then
 * drop into heuristics based on units names or common variable names.
 *
 * @param var_units The value of the 'unit' attribute
 * @param var_name The name of the variable
 * @param long_name The value of the long_name attribute
 *
 * @return true if there's a match, otherwise false
 * @see m_lon_unit_or_name_match()
 */
bool
FONgGrid::m_lat_unit_or_name_match(const string &var_units, const string &var_name,
                                   const string &long_name)
{
    return (long_name == "latitude"
            || d_coards_lat_units.find(var_units) != d_coards_lat_units.end()
            || find_if(d_lat_names.begin(), d_lat_names.end(), is_prefix(var_name)) != d_lat_names.end());
}

bool
FONgGrid::m_lon_unit_or_name_match(const string &var_units, const string &var_name,
                                   const string &long_name)
{
    return (long_name == "longitude"
            || d_coards_lon_units.find(var_units) != d_coards_lon_units.end()
            || find_if(d_lon_names.begin(), d_lon_names.end(), is_prefix(var_name)) != d_lon_names.end());
}

/** A private method called by the constructor that searches for latitude
    and longitude map vectors. This method returns false if either map
    cannot be found. It assumes that the d_grid and d_dds fields are set.

    The d_longitude, d_lon, d_lon_length and d_lon_grid_dim (and matching
    lat) fields are modified.

    @note Rules used to find Maps:

Latitude: If the Map has a units attribute of "degrees_north",
    "degree_north", "degree_N", or "degrees_N"

Longitude: If the map has a units attribute of "degrees_east"
    (eastward positive), "degree_east", "degree_E", or "degrees_E"

    @return True if the maps are found, otherwise False */
bool FONgGrid::find_lat_lon_maps()
{
    Grid::Map_iter m = d_grid->map_begin();

    // Assume that a Grid is correct and thus has exactly as many maps as its
    // array part has dimensions. Thus, don't bother to test the Grid's array
    // dimension iterator for '!= dim_end()'.
    Array::Dim_iter d = d_grid->get_array()->dim_begin();

    // The fields d_latitude and d_longitude may be initialized to null or they
    // may already contain pointers to the maps to use. In the latter case,
    // skip the heuristics used in this code. However, given that all this
    // method does is find the lat/lon maps, if they are given in the ctor,
    // This method will likely not be called at all.

    while (m != d_grid->map_end() && (!d_lat || !d_lon)) {
        string units_value = (*m)->get_attr_table().get_attr("units");
        units_value = remove_quotes(units_value);
        string long_name = (*m)->get_attr_table().get_attr("long_name");
        long_name = remove_quotes(long_name);
        string map_name = (*m)->name();

        // The 'units' attribute must match exactly; the name only needs to
        // match a prefix.
        if (!d_lat && m_lat_unit_or_name_match(units_value, map_name, long_name)) {
            // Set both d_latitude (a pointer to the real map vector) and
            // d_lat, a vector of the values represented as doubles. It's easier
            // to work with d_lat, but it's d_latitude that needs to be set
            // when constraining the grid. Also, record the grid variable's
            // dimension iterator so that it's easier to set the Grid's Array
            // (which also has to be constrained).
            d_lat = dynamic_cast < Array * >(*m);
            if (!d_lat)
                throw InternalErr(__FILE__, __LINE__, "Expected an array.");

            if (!d_lat->read_p())
                d_lat->read();
        }

        if (!d_lon && m_lon_unit_or_name_match(units_value, map_name, long_name)) {
            d_lon = dynamic_cast < Array * >(*m);
            if (!d_lon)
                throw InternalErr(__FILE__, __LINE__, "Expected an array.");

            if (!d_lon->read_p())
                d_lon->read();
        }

        ++m;
        ++d;
    }

    return d_lat && d_lon;
}

/** Extract the size (pixels), element data type and top-left and
 * bottom-right lat/lon corner points for the Grid. Also determine
 * if this is a 2D or 3D Grid and, in the latter case, ensure that
 * the first dimension is not lat or lon. In that case, the geotiff
 * will have N bands, where N is the number of elements from the
 * first dimension in the current selection.
 *
 */
void FONgGrid::extract_coordinates(FONgTransform &t)
{
    BESDEBUG("fong3", "Entering FONgGrid::extract_coordinates" << endl);

    double *lat = 0, *lon = 0;
    try {
        // Find the lat and lon maps for this Grid; throws Error
        // if the are not found.
        find_lat_lon_maps();

        // The array size
        t.set_height(d_lat->length());
        t.set_width(d_lon->length());

        lat = extract_double_array(d_lat);
        lon = extract_double_array(d_lon);

        t.set_top(lat[0]);
        t.set_left(lon[0]);
        t.set_bottom(lat[t.height() - 1]);
        t.set_right(lon[t.width() -1]);

        // Read this from the 'missing_value' or '_FillValue' attributes
        string missing_value = d_grid->get_attr_table().get_attr("missing_value");
        if (missing_value.empty())
            missing_value = d_grid->get_array()->get_attr_table().get_attr("missing_value");
        if (missing_value.empty())
            missing_value = d_grid->get_attr_table().get_attr("_FillValue");
        if (missing_value.empty())
            missing_value = d_grid->get_array()->get_attr_table().get_attr("_FillValue");

        BESDEBUG("fong3", "missing_value attribute: " << missing_value << endl);

        // NB: no_data_type() is 'none' by default
        if (!missing_value.empty()) {
            t.set_no_data(missing_value);
            if (t.no_data() < 0)
                t.set_no_data_type(FONgTransform::negative);
            else
                t.set_no_data_type(FONgTransform::positive);
        }

        t.geo_transform_set(true);

        t.set_num_bands(t.num_bands() + 1);
        t.push_var(this);

        delete[] lat;
        delete[] lon;
    }
    catch (Error &e) {
        delete[] lat;
        delete[] lon;

        throw;
    }
}

/** Use CF to determine if this is a 'Spherical Earth' datum */
static bool is_spherical(BaseType *btp)
{
    /* crs:grid_mapping_name = "latitude_longitude"
    crs:semi_major_axis = 6371000.0 ;
    crs:inverse_flattening = 0 ; */

    bool gmn = btp->get_attr_table().get_attr("grid_mapping_name") == "latitude_longitude";
    bool sma = btp->get_attr_table().get_attr("semi_major_axis") == "6371000.0";
    bool iflat = btp->get_attr_table().get_attr("inverse_flattening") == "0";

    return gmn && sma && iflat;
}

/** Use CF to determine if this is a 'WGS84' datum */
static bool is_wgs84(BaseType *btp)
{
    /*crs:grid_mapping_name = "latitude_longitude";
    crs:longitude_of_prime_meridian = 0.0 ;
    crs:semi_major_axis = 6378137.0 ;
    crs:inverse_flattening = 298.257223563 ; */

    bool gmn = btp->get_attr_table().get_attr("grid_mapping_name") == "latitude_longitude";
    bool lpm = btp->get_attr_table().get_attr("longitude_of_prime_meridian") == "0.0";
    bool sma = btp->get_attr_table().get_attr("semi_major_axis") == "6378137.0";
    bool iflat = btp->get_attr_table().get_attr("inverse_flattening") == "298.257223563";

    return gmn && lpm && sma && iflat;
}

/** @brief Set the projection information
 * For Grids, look for CF information. If it's not present, use the
 * default Geographic Coordinate system set in the bes/module conf
 * file. if it is present, look at the attributes and dope out a Well
 * Known Geographic coordinate string.
 */
string FONgGrid::get_projection(DDS *dds)
{
    // Here's the information about the CF and projections
    // http://cf-pcmdi.llnl.gov/documents/cf-conventions/1.4/cf-conventions.html#grid-mappings-and-projections
    // How this code looks for mapping information: Look for an
    // attribute named 'grid_mapping' and get it's value. This attribute
    // with be the name of a variable in the dataset, so get that
    // variable. Now, look at the attributes of that variable.
    string mapping_info = d_grid->get_attr_table().get_attr("grid_mapping");
    if (mapping_info.empty())
        mapping_info = d_grid->get_array()->get_attr_table().get_attr("grid_mapping");

    string WK_GCS = GeoTiffTransmitter::default_gcs;

    if (!mapping_info.empty()) {
        // "WGS84": same as "EPSG:4326" but has no dependence on EPSG data files.
        // "WGS72": same as "EPSG:4322" but has no dependence on EPSG data files.
        // "NAD27": same as "EPSG:4267" but has no dependence on EPSG data files.
        // "NAD83": same as "EPSG:4269" but has no dependence on EPSG data files.
        // "EPSG:n": same as doing an ImportFromEPSG(n).

        // The mapping info is actually stored as attributes of an Int32 variable.
        BaseType *btp = dds->var(mapping_info);
        if (btp->name() == "crs") {
            if (is_wgs84(btp))
                WK_GCS = "WGS84";
            else if (is_spherical(btp))
                WK_GCS = "EPSG:4047";
        }
    }

    OGRSpatialReference srs;
    srs.SetWellKnownGeogCS(WK_GCS.c_str());
    char *srs_wkt = NULL;
    srs.exportToWkt(&srs_wkt);

    string wkt = srs_wkt;   // save the result

    CPLFree(srs_wkt);       // free memory alloc'd by GDAL

    return wkt;
}

double *FONgGrid::get_data()
{
    if (!d_grid->get_array()->read_p())
        d_grid->get_array()->read();

    // This code assumes read() has been called.
    return extract_double_array(d_grid->get_array());
}

<|endoftext|>


<commit_before>#ifndef MAXWINNERTREE
#define MAXWINNERTREE
#include "MaxWinnerTree.h"
#endif

#ifndef BINARYSEARCHTREE
#define BINARYSEARCHTREE
#include "BinarySearchTree.h"
#endif

#ifndef BINARYTREENODE
#define BINARYTREENODE
#include "BinaryTreeNode.h"
#endif

#ifndef BINPACKING
#define BINPACKING
#include "BinPacking.h"
#endif
#include <stddef.h>
#include <iostream>
using namespace std;

void BinPacking::firstFitPack(int *objectSize, int numberOfObjects, int binCapacity)
{
	/*MaxWinnerTree mwtree = new MaxWinnerTree();

	// players - number of bins
	// value of player - capacity

	// init the maxwintree
	mwtree.initialize(1, binCapacity);

	/* idea of firstfitpack without tree
	int binNum = 0;

	int *currentBin = new int[binCapacity];
	int currentBinSum = 0;

	for (int i = 1; i <= numberOfObjects; i++) {
		if
		objectSize[i-1];
	}*/

	/*
	Max Winner tree

	where objectSize is the array of objects to be packed, numberofObjects is the number of Objects to be
	packed, binCapacity is the capacity of each bin.

 Bins are arranged in left to right order.
 Items are packed one at a time in the given order.
 The current item is packed into leftmost bin into which it ts.
 If there is no bin into which current item ts, start a new bin.
 Use a Max Winner tree to implement the First Fit Algorithm for the same series of numbers.
	*/

}

void BinPacking::bestFitPack(int *objectSize, int numberOfObjects, int binCapacity)
{
	cout << "== bin cap is " << binCapacity << " ==" << endl;
	cout << "object set is { " << objectSize << " } with total number of " << numberOfObjects << endl << endl;

	// make bst with dummy root as root is protected prop of binaryTree, no can modify
	BinarySearchTree *bst;

	// insert all objects
	for (int i = 1; i <= numberOfObjects; i++) {
		cout << "== object " << i << " size is " << objectSize[i-1] << " ==" << endl;

		// 1st, make new tree
		if (i == 1) {
			// init bins to one bin
			numBin = 1;
			binNumberArray = new int[numBin];

			// make new tree
			bst = new BinarySearchTree(binCapacity - objectSize[i - 1]);
			binNumberArray[i - 1] = binCapacity - objectSize[i - 1];

			cout << "new tree, now using bin " << numBin << ", insert " << objectSize[i - 1] << endl;
		}
		// yes there is bin that fits
		else if (bst->find(objectSize[i - 1]) != NULL || bst->root->capacity >= objectSize[i - 1]) {
			int foundBinNumber = 0;
			BinaryTreeNode *bin = bst->root;

			// check if root has cap (error with find function, idk)
			if (bst->root->capacity >= objectSize[i - 1]) foundBinNumber = 1;
			// not, find in tree
			else {
				bin = bst->find(objectSize[i - 1]);
				foundBin = returnedBin->binNumber; // ugh needed to change index offset this whole time
			}

			// update capacity
			int newCapacity = binNumberArray[foundBinNumber - 1] - objectSize[i - 1];
			bin->capacity = newCapacity;
			binNumberArray[foundBinNumber - 1] = newCapacity;

			// remove bin from bst if cap is now zero
			if (newCapacity == 0) bst->erase(bin);

			cout << "yes has bin, now using bin " << foundBinNumber << ", insert " << objectSize[i - 1] << endl;
		}
		// there is no bin that can fit
		else {
			// make new bin, incement numBin by one and enlarge int array
			numBin++;
			int *newBinNumberArray = new int[numBin];
			for (int j = 1; j < numBin; j++) {
				newBinNumberArray[j - 1] = binNumberArray[j - 1];
			}
			newBinNumberArray[i - 1] = objectSize[i - 1];
			binNumberArray = newBinNumberArray;

			// insert into bst if not max cap filled
			if (objectSize[i - 1] < binCapacity) bst->insert(binCapacity - objectSize[i - 1], numBin);

			cout << "no bin found, now using bin " << numBin << ", insert " << objectSize[i - 1] << endl;
		}

		// debug print bin
		for (int i = 0; i<numBin; i++) cout << binNumberArray[i] << "\t";
		cout << endl;

	}

	/*
	Binary Search Tree

	where objectSize is the array of objects to be packed, numberofObjects is the number of Objects to be
	packed, binCapacity is the capacity of each bin.

	 Items are packed one at a time in the given order.
	 To determine the bin for an item, first determine the set S of bins into which the item fits.
	 If S is empty, then start a new bin and pack the item into this new bin.
	 Otherwise, pack the item into the (in S) that has the least available capacity. If there is a tie, beak it
	with smallest binNumber.
	 Use a Binary Search Tree to implement the Best Fit Algorithm for the same series of numbers.
	*/

}<commit_msg>Rewrite without protected access<commit_after>#ifndef MAXWINNERTREE
#define MAXWINNERTREE
#include "MaxWinnerTree.h"
#endif

#ifndef BINARYSEARCHTREE
#define BINARYSEARCHTREE
#include "BinarySearchTree.h"
#endif

#ifndef BINARYTREENODE
#define BINARYTREENODE
#include "BinaryTreeNode.h"
#endif

#ifndef BINPACKING
#define BINPACKING
#include "BinPacking.h"
#endif
#include <stddef.h>
#include <iostream>
using namespace std;

void BinPacking::firstFitPack(int *objectSize, int numberOfObjects, int binCapacity)
{
	/*MaxWinnerTree mwtree = new MaxWinnerTree();

	// players - number of bins
	// value of player - capacity

	// init the maxwintree
	mwtree.initialize(1, binCapacity);

	/* idea of firstfitpack without tree
	int binNum = 0;

	int *currentBin = new int[binCapacity];
	int currentBinSum = 0;

	for (int i = 1; i <= numberOfObjects; i++) {
		if
		objectSize[i-1];
	}*/

	/*
	Max Winner tree

	where objectSize is the array of objects to be packed, numberofObjects is the number of Objects to be
	packed, binCapacity is the capacity of each bin.

 Bins are arranged in left to right order.
 Items are packed one at a time in the given order.
 The current item is packed into leftmost bin into which it ts.
 If there is no bin into which current item ts, start a new bin.
 Use a Max Winner tree to implement the First Fit Algorithm for the same series of numbers.
	*/

}

void BinPacking::bestFitPack(int *objectSize, int numberOfObjects, int binCapacity)
{
	cout << "== bin cap is " << binCapacity << " ==" << endl;
	cout << "object set is { " << objectSize << " } with total number of " << numberOfObjects << endl << endl;

	// make bst ref
	BinarySearchTree *bst;

	// insert all objects
	for (int i = 1; i <= numberOfObjects; i++) {
		cout << "== object " << i << " size is " << objectSize[i-1] << " ==" << endl;

		// 1st, make new tree
		if (i == 1) {
			// init bins to one bin
			numBin = 1;
			binNumberArray = new int[numBin];

			// make new tree
			bst = new BinarySearchTree(binCapacity - objectSize[i - 1]);
			binNumberArray[i - 1] = binCapacity - objectSize[i - 1];

			cout << "new tree, now using bin " << numBin << ", insert " << objectSize[i - 1] << endl;
		}
		// yes there is bin that fits
		else if (bst->find(objectSize[i - 1]) != NULL || bst->root->capacity >= objectSize[i - 1]) {
			int foundBinNumber = 0;

			// check if root has cap (error with overwriting root, root is protected)
			if (bst->root->capacity >= objectSize[i - 1]) {
				foundBinNumber = 1;
				bst->erase(bst->root);

				// update capacity
				int newCapacity = binNumberArray[foundBinNumber - 1] - objectSize[i - 1];
				if (newCapacity != 0) bst->insert(binNumberArray[foundBinNumber - 1] - objectSize[i - 1], foundBinNumber);
				binNumberArray[foundBinNumber - 1] = newCapacity;
			}
			// not, find in tree
			else {
				BinaryTreeNode *bin = bst->find(objectSize[i - 1]);
				foundBinNumber = bin->binNumber; // ugh needed to change index offset this whole time

				// update capacity
				int newCapacity = binNumberArray[foundBinNumber - 1] - objectSize[i - 1];
				bin->capacity = newCapacity;
				binNumberArray[foundBinNumber - 1] = newCapacity;

				// remove bin from bst if cap is now zero
				if (newCapacity == 0) bst->erase(bin);
			}

			cout << "yes has bin, now using bin " << foundBinNumber << ", insert " << objectSize[i - 1] << endl;
		}
		// there is no bin that can fit
		else {
			// make new bin, incement numBin by one and enlarge int array
			numBin++;
			int *newBinNumberArray = new int[numBin];
			for (int j = 1; j < numBin; j++) {
				newBinNumberArray[j - 1] = binNumberArray[j - 1];
			}
			newBinNumberArray[i - 1] = objectSize[i - 1];
			binNumberArray = newBinNumberArray;

			// insert into bst if not max cap filled
			if (objectSize[i - 1] < binCapacity) bst->insert(binCapacity - objectSize[i - 1], numBin);

			cout << "no bin found, now using bin " << numBin << ", insert " << objectSize[i - 1] << endl;
		}

		// debug print bin
		for (int i = 0; i<numBin; i++) cout << binNumberArray[i] << "\t";
		cout << endl;

	}

	/*
	Binary Search Tree

	where objectSize is the array of objects to be packed, numberofObjects is the number of Objects to be
	packed, binCapacity is the capacity of each bin.

	 Items are packed one at a time in the given order.
	 To determine the bin for an item, first determine the set S of bins into which the item fits.
	 If S is empty, then start a new bin and pack the item into this new bin.
	 Otherwise, pack the item into the (in S) that has the least available capacity. If there is a tie, beak it
	with smallest binNumber.
	 Use a Binary Search Tree to implement the Best Fit Algorithm for the same series of numbers.
	*/

}<|endoftext|>


<commit_before>/***********************************************************************************************************************
**
** Copyright (c) 2011, 2014 ETH Zurich
** 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.
**    * Neither the name of the ETH Zurich 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 HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
** SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
** WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
**
***********************************************************************************************************************/

#include "Node.h"
#include "../ModelBasePlugin.h"
#include "../model/TreeManager.h"
#include "../model/AllTreeManagers.h"
#include "../commands/UndoCommand.h"
#include "../ModelException.h"
#include "Reference.h"
#include "Core/src/AdapterManager.h"
#include "UsedLibrary.h"
#include "../persistence/NodeIdMap.h"

#include "../commands/NodeOwningCommand.h"

using namespace Logger;

namespace Model {

DEFINE_TYPE_ID_BASE(Node, "Node", )

/***********************************************************************************************************************
 * STATIC MEMBERS
 **********************************************************************************************************************/
QHash<QString, Node::NodeConstructor> Node::nodeConstructorRegister;
QHash<QString, Node::NodePersistenceConstructor> Node::nodePersistenceConstructorRegister;

QSet<const Node*>& Node::partiallyLoadedNodes()
{
	static QSet<const Node*> set;
	return set;
}

/***********************************************************************************************************************
 * CONSTRUCTORS AND DESTRUCTORS
 **********************************************************************************************************************/
Node::Node(Node* parent) : parent_{parent}, manager_{parent ? parent->manager_ : nullptr}
{
	if (parent && !parent->isModifyable())
		throw ModelException("Trying to create a node with a non-modifiable parent.");
}

Node::Node(const Node&) : Node{nullptr} {}

Node::~Node()
{
	partiallyLoadedNodes().remove(this);

	for (auto m : AllTreeManagers::instance().loadedManagers())
		m->nodeIdMap().remove(this);
}

Node* Node::createDefaultInstance(Node*)
{
	Q_ASSERT(false);
	return nullptr;
}

/***********************************************************************************************************************
 * MAIN METHODS
 **********************************************************************************************************************/
void Node::execute(UndoCommand *command)
{
	if ( this != command->target() )
		throw ModelException("Command target differs from current node when executing commands");

	TreeManager* m = manager();

	bool hasOwnTreeManager = m;

	// The if below is needed to make it possible to use nodes already attached in the tree, in the set method
	// of new nodes, which are not yet attached. Without it this command will not be recorded in the undo stack.
	if (auto owning = dynamic_cast<NodeOwningCommand*>(command))
	{
		auto managerOfInserted = owning->insertedNode() ?
			AllTreeManagers::instance().managerOfOwningUndoStack(owning->insertedNode()) : nullptr;
		if (!m) m = managerOfInserted;
		else Q_ASSERT(!managerOfInserted || m == managerOfInserted);
		auto managerOfRemoved = owning->removedNode() ?
			AllTreeManagers::instance().managerOfOwningUndoStack(owning->removedNode()) : nullptr;
		if (!m) m = managerOfRemoved;
		else Q_ASSERT(!managerOfRemoved || m == managerOfRemoved);
	}

	if (m)
	{
		if (hasOwnTreeManager && !m->canBeModified(this) ) throw ModelException("Can not modify the current node.");
		m->pushCommandOnUndoStack(command);
	}
	else
	{
		command->redo();
		SAFE_DELETE(command);
	}
}

Node* Node::lowestCommonAncestor(Node* other, Node** thisParent, Node** otherParent)
{
	QList<Node*> thisParents;
	QList<Node*> otherParents;

	// Get all parents of the current node
	Node* n = this;
	while ( n )
	{
		thisParents.prepend(n);
		n = n->parent();
	}

	// Get all parents of the other node
	n = other;
	while ( n )
	{
		otherParents.prepend(n);
		n = n->parent();
	}

	// Find the lowest common ancestor
	n = nullptr;
	while ( thisParents.size() > 0 && otherParents.size() > 0 && thisParents.first() == otherParents.first() )
	{
		n = thisParents.first();

		thisParents.removeFirst();
		otherParents.removeFirst();
	}

	Q_ASSERT(thisParents.isEmpty() == otherParents.isEmpty());
	if (thisParent)
	{
		if (thisParents.isEmpty()) *thisParent = nullptr;
		else *thisParent = thisParents.first();
	}
	if (otherParent)
	{
		if (otherParents.isEmpty()) *otherParent = nullptr;
		else *otherParent = otherParents.first();
	}

	return n;
}

bool Node::isAncestorOf(const Node* other) const
{
	if (other == nullptr) return false;

	const Node* p = other->parent();

	while (p && p != this) p = p->parent();

	return p == this;
}

Node* Node::firstAncestorOfType(const SymbolMatcher& typeMatch) const
{
	auto typeOrSubtypeMatches = [typeMatch](Model::Node* node) {
		if (typeMatch.isFixedString())
			return node->isSubtypeOf(typeMatch.matchPattern());
		return typeMatch.matches(node->typeName());
	};
	auto p = parent();
	while (p && !typeOrSubtypeMatches(p)) p = p->parent();
	return p;
}

Node* Node::childToSubnode(const Node* other) const
{
	if (other == nullptr) return nullptr;

	const Node* child = other;
	const Node* parent = child->parent();

	while (parent && parent != this)
	{
		child = parent;
		parent = child->parent();
	}

	return parent == this ? const_cast<Node*>(child) : nullptr;
}

bool Node::isModifyable() const
{
	TreeManager* m = manager();

	return !m || m->canBeModified(this);
}

bool Node::replaceChild(Node*, Node*)
{
	return false;
}

bool Node::findSymbols(QSet<Node*>& result, const SymbolMatcher& matcher, const Node* source,
		FindSymbolDirection direction, SymbolTypes symbolTypes, bool exhaustAllScopes) const
{
	bool found{};

	if (direction == SEARCH_HERE && !isTransparentForNameResolution())
	{
		if (symbolMatches(matcher, symbolTypes))
		{
			found = true;
			result.insert(const_cast<Node*>(this));
		}
	}
	else if (direction == SEARCH_DOWN || (direction == SEARCH_HERE && isTransparentForNameResolution()))
	{
		for (auto c : childrenInScope())
			found = c->findSymbols(result, matcher, source, SEARCH_HERE, symbolTypes, false) || found;
	}
	else if (direction == SEARCH_UP)
	{
		auto ignore = childToSubnode(source);
		for (auto c : childrenInScope())
			if (c != ignore) // Optimize the search by skipping this scope, since we've already searched there
				found = c->findSymbols(result, matcher, source, SEARCH_HERE, symbolTypes, false) || found;

		if ((exhaustAllScopes || !found) && symbolMatches(matcher, symbolTypes) && !isTransparentForNameResolution())
		{
			found = true;
			result.insert(const_cast<Node*>(this));
		}

		if ((exhaustAllScopes || !found) && parent_)
			found = parent_->findSymbols(result, matcher, source, SEARCH_UP, symbolTypes, exhaustAllScopes) || found;

		// Search in libraries. This is only valid for root nodes
		if ((exhaustAllScopes || !found) && !parent_)
			for (const UsedLibrary* lib : usedLibraries())
			{
				auto libRoot = lib->libraryRoot();
				if (libRoot)
					found = libRoot->findSymbols(result, matcher, libRoot, SEARCH_DOWN, symbolTypes, exhaustAllScopes)
							|| found;
			}
	}

	return found;
}

QList<Node*> Node::childrenInScope() const
{
	return children();
}

void Node::beginModification(const QString &text)
{
	if (auto m = manager())
		m->beginModification(this, text);
}

void Node::endModification()
{
	if (auto m = manager()) m->endModification();
}

QString Node::toDebugString()
{
	auto ntdsa = Core::AdapterManager::adapt<NodeToDebugStringAdapter>(this);

	QString ret = ntdsa ? ntdsa->str : "no debug string for node";
	SAFE_DELETE(ntdsa);
	return ret;
}

bool Node::hasPartiallyLoadedChildren() const
{
	if (isPartiallyLoaded()) return true;

	return false;
}
/***********************************************************************************************************************
 * GETTERS AND SETTERS
 **********************************************************************************************************************/
void Node::setParent(Node* parent)
{
	parent_ = parent;
	auto oldManager = manager_;
	manager_ = parent ? parent->manager_ : nullptr;
	if (oldManager != manager_)	propagateManagerToChildren();

	if (manager_) Reference::unresolveAfterNewSubTree(this);
}

void Node::propagateManagerToChildren()
{
	QList<Node*> stack;
	stack.append(children());
	while (!stack.isEmpty())
	{
		auto top = stack.takeLast();
		top->manager_ = manager_;
		stack.append(top->children());
	}
}

void Node::setRootManager(TreeManager* manager)
{
	Q_ASSERT(!parent_);
	Q_ASSERT(manager);
	manager_ = manager;
	propagateManagerToChildren();
}

QList<Node*> Node::children() const
{
	return QList<Node*>();
}

bool Node::definesSymbol() const
{
	return false;
}

bool Node::isTransparentForNameResolution() const
{
	return false;
}

const QString& Node::symbolName() const
{
	static QString nullString;
	return nullString;
}

Node::SymbolTypes Node::symbolType() const
{
	return UNSPECIFIED;
}

bool Node::isNewPersistenceUnit() const
{
	return false;
}

Node* Node::persistentUnitNode() const
{
	const Node* persistentUnitNode = this;
	const Node* prev = this;

	while ( persistentUnitNode && persistentUnitNode->isNewPersistenceUnit() == false )
	{
		prev = persistentUnitNode;
		persistentUnitNode = persistentUnitNode->parent();
	}

	if (persistentUnitNode) return const_cast<Node*> (persistentUnitNode);
	else return const_cast<Node*> (prev);
}

int Node::revision() const
{
	return revision_;
}

void Node::incrementRevision()
{
	revision_++;
}

void Node::addToRevision(int valueToAdd)
{
	revision_ += valueToAdd;
}

NodeReadWriteLock* Node::accessLock() const
{
	if ( parent_ ) return parent_->accessLock();
	else
		return manager()->rootLock();
}

QList<const UsedLibrary*> Node::usedLibraries() const
{
	QList<const UsedLibrary*> all;
	for (auto c : children())
		all << c->usedLibraries();
	return all;
}

/***********************************************************************************************************************
 * STATIC METHODS
 **********************************************************************************************************************/
void Node::registerNodeType(const QString &type, const NodeConstructor constructor,
		const NodePersistenceConstructor persistenceconstructor)
{
	if ( isTypeRegistered(type) )
		throw ModelException("Trying to register a node type that has already been registered: " + type);

	nodeConstructorRegister.insert(type, constructor);
	nodePersistenceConstructorRegister.insert(type, persistenceconstructor);

	log.info("Registered new node type " + type);
}

Node* Node::createNewNode(const QString &type, Node* parent)
{
	auto iter = nodeConstructorRegister.find(type);
	if ( iter != nodeConstructorRegister.end() )
	{
		return iter.value()(parent);
	}
	else
	{
		log.error("Could not create new node. Requested node type '"
				+ type +"' has not been registered.");
		return nullptr;
	}
}

Node* Node::createNewNode(const QString &type, Node* parent, PersistentStore &store, bool partialLoadHint)
{
	auto iter = nodePersistenceConstructorRegister.find(type);
	if ( iter != nodePersistenceConstructorRegister.end() )
	{
		return iter.value()(parent, store, partialLoadHint);
	}
	else
	{
		log.error("Could not create new node from persistence. Requested node type '"
				+ type + "' has not been registered.");
		return nullptr;
	}
}

bool Node::isTypeRegistered(const QString &type)
{
	return nodeConstructorRegister.contains(type);
}

}
<commit_msg>remove unused using declaration<commit_after>/***********************************************************************************************************************
**
** Copyright (c) 2011, 2014 ETH Zurich
** 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.
**    * Neither the name of the ETH Zurich 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 HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
** SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
** WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
**
***********************************************************************************************************************/

#include "Node.h"
#include "../ModelBasePlugin.h"
#include "../model/TreeManager.h"
#include "../model/AllTreeManagers.h"
#include "../commands/UndoCommand.h"
#include "../ModelException.h"
#include "Reference.h"
#include "Core/src/AdapterManager.h"
#include "UsedLibrary.h"
#include "../persistence/NodeIdMap.h"

#include "../commands/NodeOwningCommand.h"

namespace Model {

DEFINE_TYPE_ID_BASE(Node, "Node", )

/***********************************************************************************************************************
 * STATIC MEMBERS
 **********************************************************************************************************************/
QHash<QString, Node::NodeConstructor> Node::nodeConstructorRegister;
QHash<QString, Node::NodePersistenceConstructor> Node::nodePersistenceConstructorRegister;

QSet<const Node*>& Node::partiallyLoadedNodes()
{
	static QSet<const Node*> set;
	return set;
}

/***********************************************************************************************************************
 * CONSTRUCTORS AND DESTRUCTORS
 **********************************************************************************************************************/
Node::Node(Node* parent) : parent_{parent}, manager_{parent ? parent->manager_ : nullptr}
{
	if (parent && !parent->isModifyable())
		throw ModelException("Trying to create a node with a non-modifiable parent.");
}

Node::Node(const Node&) : Node{nullptr} {}

Node::~Node()
{
	partiallyLoadedNodes().remove(this);

	for (auto m : AllTreeManagers::instance().loadedManagers())
		m->nodeIdMap().remove(this);
}

Node* Node::createDefaultInstance(Node*)
{
	Q_ASSERT(false);
	return nullptr;
}

/***********************************************************************************************************************
 * MAIN METHODS
 **********************************************************************************************************************/
void Node::execute(UndoCommand *command)
{
	if ( this != command->target() )
		throw ModelException("Command target differs from current node when executing commands");

	TreeManager* m = manager();

	bool hasOwnTreeManager = m;

	// The if below is needed to make it possible to use nodes already attached in the tree, in the set method
	// of new nodes, which are not yet attached. Without it this command will not be recorded in the undo stack.
	if (auto owning = dynamic_cast<NodeOwningCommand*>(command))
	{
		auto managerOfInserted = owning->insertedNode() ?
			AllTreeManagers::instance().managerOfOwningUndoStack(owning->insertedNode()) : nullptr;
		if (!m) m = managerOfInserted;
		else Q_ASSERT(!managerOfInserted || m == managerOfInserted);
		auto managerOfRemoved = owning->removedNode() ?
			AllTreeManagers::instance().managerOfOwningUndoStack(owning->removedNode()) : nullptr;
		if (!m) m = managerOfRemoved;
		else Q_ASSERT(!managerOfRemoved || m == managerOfRemoved);
	}

	if (m)
	{
		if (hasOwnTreeManager && !m->canBeModified(this) ) throw ModelException("Can not modify the current node.");
		m->pushCommandOnUndoStack(command);
	}
	else
	{
		command->redo();
		SAFE_DELETE(command);
	}
}

Node* Node::lowestCommonAncestor(Node* other, Node** thisParent, Node** otherParent)
{
	QList<Node*> thisParents;
	QList<Node*> otherParents;

	// Get all parents of the current node
	Node* n = this;
	while ( n )
	{
		thisParents.prepend(n);
		n = n->parent();
	}

	// Get all parents of the other node
	n = other;
	while ( n )
	{
		otherParents.prepend(n);
		n = n->parent();
	}

	// Find the lowest common ancestor
	n = nullptr;
	while ( thisParents.size() > 0 && otherParents.size() > 0 && thisParents.first() == otherParents.first() )
	{
		n = thisParents.first();

		thisParents.removeFirst();
		otherParents.removeFirst();
	}

	Q_ASSERT(thisParents.isEmpty() == otherParents.isEmpty());
	if (thisParent)
	{
		if (thisParents.isEmpty()) *thisParent = nullptr;
		else *thisParent = thisParents.first();
	}
	if (otherParent)
	{
		if (otherParents.isEmpty()) *otherParent = nullptr;
		else *otherParent = otherParents.first();
	}

	return n;
}

bool Node::isAncestorOf(const Node* other) const
{
	if (other == nullptr) return false;

	const Node* p = other->parent();

	while (p && p != this) p = p->parent();

	return p == this;
}

Node* Node::firstAncestorOfType(const SymbolMatcher& typeMatch) const
{
	auto typeOrSubtypeMatches = [typeMatch](Model::Node* node) {
		if (typeMatch.isFixedString())
			return node->isSubtypeOf(typeMatch.matchPattern());
		return typeMatch.matches(node->typeName());
	};
	auto p = parent();
	while (p && !typeOrSubtypeMatches(p)) p = p->parent();
	return p;
}

Node* Node::childToSubnode(const Node* other) const
{
	if (other == nullptr) return nullptr;

	const Node* child = other;
	const Node* parent = child->parent();

	while (parent && parent != this)
	{
		child = parent;
		parent = child->parent();
	}

	return parent == this ? const_cast<Node*>(child) : nullptr;
}

bool Node::isModifyable() const
{
	TreeManager* m = manager();

	return !m || m->canBeModified(this);
}

bool Node::replaceChild(Node*, Node*)
{
	return false;
}

bool Node::findSymbols(QSet<Node*>& result, const SymbolMatcher& matcher, const Node* source,
		FindSymbolDirection direction, SymbolTypes symbolTypes, bool exhaustAllScopes) const
{
	bool found{};

	if (direction == SEARCH_HERE && !isTransparentForNameResolution())
	{
		if (symbolMatches(matcher, symbolTypes))
		{
			found = true;
			result.insert(const_cast<Node*>(this));
		}
	}
	else if (direction == SEARCH_DOWN || (direction == SEARCH_HERE && isTransparentForNameResolution()))
	{
		for (auto c : childrenInScope())
			found = c->findSymbols(result, matcher, source, SEARCH_HERE, symbolTypes, false) || found;
	}
	else if (direction == SEARCH_UP)
	{
		auto ignore = childToSubnode(source);
		for (auto c : childrenInScope())
			if (c != ignore) // Optimize the search by skipping this scope, since we've already searched there
				found = c->findSymbols(result, matcher, source, SEARCH_HERE, symbolTypes, false) || found;

		if ((exhaustAllScopes || !found) && symbolMatches(matcher, symbolTypes) && !isTransparentForNameResolution())
		{
			found = true;
			result.insert(const_cast<Node*>(this));
		}

		if ((exhaustAllScopes || !found) && parent_)
			found = parent_->findSymbols(result, matcher, source, SEARCH_UP, symbolTypes, exhaustAllScopes) || found;

		// Search in libraries. This is only valid for root nodes
		if ((exhaustAllScopes || !found) && !parent_)
			for (const UsedLibrary* lib : usedLibraries())
			{
				auto libRoot = lib->libraryRoot();
				if (libRoot)
					found = libRoot->findSymbols(result, matcher, libRoot, SEARCH_DOWN, symbolTypes, exhaustAllScopes)
							|| found;
			}
	}

	return found;
}

QList<Node*> Node::childrenInScope() const
{
	return children();
}

void Node::beginModification(const QString &text)
{
	if (auto m = manager())
		m->beginModification(this, text);
}

void Node::endModification()
{
	if (auto m = manager()) m->endModification();
}

QString Node::toDebugString()
{
	auto ntdsa = Core::AdapterManager::adapt<NodeToDebugStringAdapter>(this);

	QString ret = ntdsa ? ntdsa->str : "no debug string for node";
	SAFE_DELETE(ntdsa);
	return ret;
}

bool Node::hasPartiallyLoadedChildren() const
{
	if (isPartiallyLoaded()) return true;

	return false;
}
/***********************************************************************************************************************
 * GETTERS AND SETTERS
 **********************************************************************************************************************/
void Node::setParent(Node* parent)
{
	parent_ = parent;
	auto oldManager = manager_;
	manager_ = parent ? parent->manager_ : nullptr;
	if (oldManager != manager_)	propagateManagerToChildren();

	if (manager_) Reference::unresolveAfterNewSubTree(this);
}

void Node::propagateManagerToChildren()
{
	QList<Node*> stack;
	stack.append(children());
	while (!stack.isEmpty())
	{
		auto top = stack.takeLast();
		top->manager_ = manager_;
		stack.append(top->children());
	}
}

void Node::setRootManager(TreeManager* manager)
{
	Q_ASSERT(!parent_);
	Q_ASSERT(manager);
	manager_ = manager;
	propagateManagerToChildren();
}

QList<Node*> Node::children() const
{
	return QList<Node*>();
}

bool Node::definesSymbol() const
{
	return false;
}

bool Node::isTransparentForNameResolution() const
{
	return false;
}

const QString& Node::symbolName() const
{
	static QString nullString;
	return nullString;
}

Node::SymbolTypes Node::symbolType() const
{
	return UNSPECIFIED;
}

bool Node::isNewPersistenceUnit() const
{
	return false;
}

Node* Node::persistentUnitNode() const
{
	const Node* persistentUnitNode = this;
	const Node* prev = this;

	while ( persistentUnitNode && persistentUnitNode->isNewPersistenceUnit() == false )
	{
		prev = persistentUnitNode;
		persistentUnitNode = persistentUnitNode->parent();
	}

	if (persistentUnitNode) return const_cast<Node*> (persistentUnitNode);
	else return const_cast<Node*> (prev);
}

int Node::revision() const
{
	return revision_;
}

void Node::incrementRevision()
{
	revision_++;
}

void Node::addToRevision(int valueToAdd)
{
	revision_ += valueToAdd;
}

NodeReadWriteLock* Node::accessLock() const
{
	if ( parent_ ) return parent_->accessLock();
	else
		return manager()->rootLock();
}

QList<const UsedLibrary*> Node::usedLibraries() const
{
	QList<const UsedLibrary*> all;
	for (auto c : children())
		all << c->usedLibraries();
	return all;
}

/***********************************************************************************************************************
 * STATIC METHODS
 **********************************************************************************************************************/
void Node::registerNodeType(const QString &type, const NodeConstructor constructor,
		const NodePersistenceConstructor persistenceconstructor)
{
	if ( isTypeRegistered(type) )
		throw ModelException("Trying to register a node type that has already been registered: " + type);

	nodeConstructorRegister.insert(type, constructor);
	nodePersistenceConstructorRegister.insert(type, persistenceconstructor);

	log.info("Registered new node type " + type);
}

Node* Node::createNewNode(const QString &type, Node* parent)
{
	auto iter = nodeConstructorRegister.find(type);
	if ( iter != nodeConstructorRegister.end() )
	{
		return iter.value()(parent);
	}
	else
	{
		log.error("Could not create new node. Requested node type '"
				+ type +"' has not been registered.");
		return nullptr;
	}
}

Node* Node::createNewNode(const QString &type, Node* parent, PersistentStore &store, bool partialLoadHint)
{
	auto iter = nodePersistenceConstructorRegister.find(type);
	if ( iter != nodePersistenceConstructorRegister.end() )
	{
		return iter.value()(parent, store, partialLoadHint);
	}
	else
	{
		log.error("Could not create new node from persistence. Requested node type '"
				+ type + "' has not been registered.");
		return nullptr;
	}
}

bool Node::isTypeRegistered(const QString &type)
{
	return nodeConstructorRegister.contains(type);
}

}
<|endoftext|>


<commit_before>/**
 * Copyright (C) 2002-2004, Tamer Fahmy <tamer@tammura.at>
 * 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.
 *   * Neither the name of the copyright holder 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 <Python.h>

#include <Inventor/actions/SoAudioRenderAction.h>
#include <Inventor/actions/SoCallbackAction.h>
#include <Inventor/actions/SoGetBoundingBoxAction.h>
#include <Inventor/actions/SoGetMatrixAction.h>
#include <Inventor/actions/SoGLRenderAction.h>
#include <Inventor/actions/SoHandleEventAction.h>
#include <Inventor/actions/SoPickAction.h>
#include <Inventor/actions/SoGetPrimitiveCountAction.h>
#include <Inventor/actions/SoRayPickAction.h>
#include <Inventor/actions/SoSearchAction.h>
#include <Inventor/actions/SoWriteAction.h>
#include <Inventor/errors/SoDebugError.h>
#include <Inventor/errors/SoReadError.h>
#include <Inventor/C/tidbits.h>

#include "SoPyScript.h"

/* SWIG runtime definitions */
typedef void *(*swig_converter_func)(void *);
typedef struct swig_type_info *(*swig_dycast_func)(void **);

typedef struct swig_type_info {
  const char             *name;
  swig_converter_func     converter;
  const char             *str;
  void                   *clientdata;
  swig_dycast_func        dcast;
  struct swig_type_info  *next;
  struct swig_type_info  *prev;
} swig_type_info;

#define SWIG_ConvertPtr(obj, pp, type, flags) \
  SWIG_Python_ConvertPtr(obj, pp, type, flags)
#define SWIG_NewPointerObj(p, type, flags) \
  SWIG_Python_NewPointerObj(p, type, flags)
#define SWIG_TypeQuery SWIG_Python_TypeQuery

extern "C" {
int SWIG_Python_ConvertPtr(PyObject *, void **, swig_type_info *, int);
PyObject * SWIG_Python_NewPointerObj(void *, swig_type_info *,int own);
swig_type_info * SWIG_TypeQuery(const char *);
}

SoType SoPyScript::classTypeId;

void
SoPyScript::initClass(void)
{
  SoPyScript::classTypeId =
    SoType::createType(SoNode::getClassTypeId(),
                       SbName("SoPyScript"),
                       SoPyScript::createInstance,
                       SoNode::nextActionMethodIndex++);
  SoNode::setCompatibilityTypes(SoPyScript::getClassTypeId(),
                                SoNode::COIN_2_0|SoNode::COIN_2_2|SoNode::COIN_2_3|SoNode::COIN_2_4);

  Py_Initialize();
}

SoPyScript::SoPyScript(void)
  : fielddata(NULL)
{
  this->isBuiltIn = FALSE;
  assert(SoPyScript::classTypeId != SoType::badType());

  this->script.setValue(NULL);
  this->script.setContainer(this);

  if (this->fielddata) delete this->fielddata;
  this->fielddata = new SoFieldData;
  this->fielddata->addField(this, "script", &this->script);

  if (!(thread_state = Py_NewInterpreter())) {
    SoDebugError::postWarning("SoPyScript::initClass",
                              "Creation of new sub-interpreter failed!");
  }

  if (PyRun_SimpleString("from pivy import *")) {
    SoDebugError::postWarning("SoPyScript::initClass",
                              "\n*Yuk!* The box containing a fierce looking python snake to drive\n"
                              "this node has arrived but was found to be empty! The Pivy module\n"
                              "required for the Python Scripting Node could not be successfully\n"
                              "imported! Check your setup and fix it so that the python snake can\n"
                              "happily wiggle and byte you in the ass...");
  }

  PyThreadState * tstate = PyThreadState_Swap((PyThreadState*)thread_state);
  Py_SetProgramName("SoPyScript");
  this->globalModuleDict = PyModule_GetDict(PyImport_AddModule("__main__"));

  /* shovel the the node itself on to the Python interpreter as self instance */
  swig_type_info * swig_type = 0;

  if ((swig_type = SWIG_TypeQuery("SoNode *")) == 0) {
    SoDebugError::post("SoPyScript::SoPyScript",
                       "No SoPyscript SWIG type found!");
  }

  /* add the field to the global dict */
  PyDict_SetItemString((PyObject*)this->globalModuleDict,
                       "self",
                       SWIG_NewPointerObj((void *)this, swig_type, 0));

  PyThreadState_Swap(tstate);
}

SoPyScript::~SoPyScript()
{
  Py_EndInterpreter((PyThreadState*)thread_state);

  const int n = this->fielddata->getNumFields();
  for (int i = 0; i < n; i++) {
    SoField * f = this->fielddata->getField(this, i);
    if (f != &this->script) delete f;
  }
  delete this->fielddata;
}

// Doc in parent
SoType
SoPyScript::getClassTypeId(void)
{
  return SoPyScript::classTypeId;
}

// Doc in parent
SoType
SoPyScript::getTypeId(void) const
{
  return SoPyScript::classTypeId;
}

// Doc in parent
void *
SoPyScript::createInstance(void)
{
  return (void*) new SoPyScript;
}

// Doc in parent
const SoFieldData *
SoPyScript::getFieldData(void) const
{
  return this->fielddata;
}

SbBool
SoPyScript::readInstance(SoInput * in, unsigned short flags)
{
  SbString name, typeVal;

  /* read in the first string */
  if (in->read(typeVal) && typeVal == "fields") {
    if (in->read(typeVal) && typeVal == "[") {

      while (in->read(typeVal) && typeVal != "]") {
        SoType type = SoType::fromName(typeVal);

        /* if it denotes a valid type and is derived from SoField then
           read in the next string representing the name of the
           field */
        if (type != SoType::badType() &&
            type.isDerivedFrom(SoField::getClassTypeId()) &&
            in->read(name))
        {
          // check for a comma at the end and strip it off
          const char * fieldname =
            (name[name.getLength()-1] == ',') ? name.getSubString(0, name.getLength()-2).getString() : name.getString();

          /* skip the script field */
          if (!strcmp(fieldname, "script")) { continue; }

          /* instantiate the field and conduct similar actions as the
             SO_NODE_ADD_FIELD macro */
          SoField * field = (SoField *)type.createInstance();
          field->setContainer(this);
          this->fielddata->addField(this, fieldname, field);

          /* shovel the field instance on to the Python interpreter */
          swig_type_info * swig_type = 0;

          /* FIXME: query if the So prefix is needed or not by calling
             the node->getIsBuiltIn() method. 20041012 tamer. */
          typeVal += " *";
          if ((swig_type = SWIG_TypeQuery(typeVal.getString())) == 0) {
            /* FIXME: if soTypeVal is created on the stack, the stack
               gets corrupted. why is this so, by the big fat ass of
               teutates??? 20041012 tamer. */
            /* try again by prefixing the typename with So */
            SbString * soTypeVal = new SbString("So");
            *soTypeVal += typeVal;
            if ((swig_type = SWIG_TypeQuery(soTypeVal->getString())) == 0) {
              SoDebugError::post("SoPyScript::readInstance",
                                 "%s unknown to Pivy!", typeVal.getString());

              return FALSE;
            }
            delete soTypeVal;
          }
          PyThreadState * tstate = PyThreadState_Swap((PyThreadState*)thread_state);

          /* add the field to the global dict */
          PyDict_SetItemString((PyObject*)this->globalModuleDict,
                               fieldname,
                               SWIG_NewPointerObj((void *)field, swig_type, 0));
          PyThreadState_Swap(tstate);
        }
      }
    }
  }

  /* ...and let the regular readInstance() method parse the rest */
  SbBool ok = inherited::readInstance(in, flags);

  PyThreadState * tstate = PyThreadState_Swap((PyThreadState*)thread_state);
  PyRun_SimpleString((char *)script.getValue().getString());
  if (coin_getenv("PIVY_DEBUG")) {
    SoDebugError::postInfo("SoPyScript::readInstance",
                           "script executed at full length!");
  }
  PyThreadState_Swap(tstate);

  return ok;
}

void
SoPyScript::doAction(SoAction * action, const char * funcname)
{
  if (funcname && !script.isIgnored()) {
    PyThreadState * tstate = PyThreadState_Swap((PyThreadState*)thread_state);

    if (coin_getenv("PIVY_DEBUG")) {
      SoDebugError::postInfo("SoPyScript::doAction",
                             "%s called!", action->getTypeId().getName().getString());
      SoDebugError::postInfo("SoPyScript::doAction",
                             "threadstate=%p:%p", tstate, thread_state);
    }

    /* convert the action instance to a Python object */
    swig_type_info * swig_type = 0;

    SbString typeVal(action->getTypeId().getName().getString());

    /* FIXME: query if the So prefix is needed or not by calling
       the node->getIsBuiltIn() method. 20041012 tamer. */
    typeVal += " *";
    if ((swig_type = SWIG_TypeQuery(typeVal.getString())) == 0) {
      /* FIXME: if soTypeVal is created on the stack, the stack gets
         corrupted. why is this so, by the big fat ass of teutates???
         20041012 tamer. */
      /* try again by prefixing the typename with So */
      SbString * soTypeVal = new SbString("So");
      *soTypeVal += typeVal;
      if ((swig_type = SWIG_TypeQuery(soTypeVal->getString())) == 0) {
        SoDebugError::post("SoPyScript::doAction",
                           "%s unknown to Pivy!", typeVal.getString());
      }
      delete soTypeVal;
    }

    if (coin_getenv("PIVY_DEBUG")) {
      SoDebugError::postInfo("SoPyScript::doAction",
                             "typeVal: %s", typeVal.getString());
    }

    PyObject * func = PyDict_GetItemString((PyObject*)this->globalModuleDict, funcname);
    PyObject * pyAction = NULL;

    if (swig_type) {
      pyAction = SWIG_NewPointerObj((void *) action, swig_type, 0);
    }

    PyObject * argtuple = NULL;
    argtuple = Py_BuildValue("(O)", pyAction);

    if (coin_getenv("PIVY_DEBUG")) {
      SoDebugError::postInfo("SoPyScript::doAction",
                             "funcname: %s, func: %p, argtuple: %p",
                             funcname, func, argtuple);
    }

    if (func && argtuple) {
      if (!PyCallable_Check(func)) {
        SbString errMsg(funcname);
        errMsg += " is not a callable object!";
        PyErr_SetString(PyExc_TypeError, errMsg.getString());
      } else {
        PyObject * result;
        if ((result = PyEval_CallObject(func, argtuple)) == NULL) {
          PyErr_Print();
        }
        Py_XDECREF(result);
      }

      Py_DECREF(argtuple);
      Py_DECREF(pyAction);
    }

    // PyRun_SimpleString((char *)script.getValue().getString());
    PyThreadState_Swap(tstate);
  }
  inherited::doAction(action);
}

void
SoPyScript::GLRender(SoGLRenderAction * action)
{
  SoPyScript::doAction(action, "GLRender");
  inherited::GLRender(action);
}

void
SoPyScript::GLRenderBelowPath(SoGLRenderAction * action)
{
  SoPyScript::doAction(action, "GLRenderBelowPath");
  inherited::GLRenderBelowPath(action);
}

void
SoPyScript::GLRenderInPath(SoGLRenderAction * action)
{
  SoPyScript::doAction(action, "GLRenderInPath");
  inherited::GLRenderInPath(action);
}

void
SoPyScript::GLRenderOffPath(SoGLRenderAction * action)
{
  SoPyScript::doAction(action, "GLRenderOffPath");
  inherited::GLRenderOffPath(action);
}

void
SoPyScript::callback(SoCallbackAction * action)
{
  SoPyScript::doAction(action, "callback");
  inherited::callback(action);
}

void
SoPyScript::getBoundingBox(SoGetBoundingBoxAction * action)
{
  SoPyScript::doAction(action, "getBoundingBox");
  inherited::getBoundingBox(action);
}

void
SoPyScript::getMatrix(SoGetMatrixAction * action)
{
  SoPyScript::doAction(action, "getMatrix");
  inherited::getMatrix(action);
}

void
SoPyScript::handleEvent(SoHandleEventAction * action)
{
  SoPyScript::doAction(action, "handleEvent");
  inherited::handleEvent(action);
}

void
SoPyScript::pick(SoPickAction * action)
{
  SoPyScript::doAction(action, "pick");
  inherited::pick(action);
}

void
SoPyScript::rayPick(SoRayPickAction * action)
{
  SoPyScript::doAction(action, "rayPick");
  inherited::rayPick(action);
}

void
SoPyScript::search(SoSearchAction * action)
{
  SoPyScript::doAction(action, "search");
  inherited::search(action);
}

void
SoPyScript::write(SoWriteAction * action)
{
  SoPyScript::doAction(action, "write");
  inherited::write(action);
}

void
SoPyScript::audioRender(SoAudioRenderAction * action)
{
  SoPyScript::doAction(action, "audioRender");
  inherited::audioRender(action);
}

void
SoPyScript::getPrimitiveCount(SoGetPrimitiveCountAction * action)
{
  SoPyScript::doAction(action, "getPrimitiveCount");
  inherited::getPrimitiveCount(action);
}
<commit_msg>cosmetics...<commit_after>/**
 * Copyright (C) 2002-2004, Tamer Fahmy <tamer@tammura.at>
 * 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.
 *   * Neither the name of the copyright holder 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 <Python.h>

#include <Inventor/actions/SoAudioRenderAction.h>
#include <Inventor/actions/SoCallbackAction.h>
#include <Inventor/actions/SoGetBoundingBoxAction.h>
#include <Inventor/actions/SoGetMatrixAction.h>
#include <Inventor/actions/SoGLRenderAction.h>
#include <Inventor/actions/SoHandleEventAction.h>
#include <Inventor/actions/SoPickAction.h>
#include <Inventor/actions/SoGetPrimitiveCountAction.h>
#include <Inventor/actions/SoRayPickAction.h>
#include <Inventor/actions/SoSearchAction.h>
#include <Inventor/actions/SoWriteAction.h>
#include <Inventor/errors/SoDebugError.h>
#include <Inventor/errors/SoReadError.h>
#include <Inventor/C/tidbits.h>

#include "SoPyScript.h"

/* SWIG runtime definitions */
typedef void *(*swig_converter_func)(void *);
typedef struct swig_type_info *(*swig_dycast_func)(void **);

typedef struct swig_type_info {
  const char             *name;
  swig_converter_func     converter;
  const char             *str;
  void                   *clientdata;
  swig_dycast_func        dcast;
  struct swig_type_info  *next;
  struct swig_type_info  *prev;
} swig_type_info;

#define SWIG_NewPointerObj SWIG_Python_NewPointerObj
#define SWIG_TypeQuery SWIG_Python_TypeQuery

extern "C" {
PyObject * SWIG_Python_NewPointerObj(void *, swig_type_info *,int own);
swig_type_info * SWIG_TypeQuery(const char *);
}

SoType SoPyScript::classTypeId;

void
SoPyScript::initClass(void)
{
  SoPyScript::classTypeId =
    SoType::createType(SoNode::getClassTypeId(),
                       SbName("SoPyScript"),
                       SoPyScript::createInstance,
                       SoNode::nextActionMethodIndex++);
  SoNode::setCompatibilityTypes(SoPyScript::getClassTypeId(),
                                SoNode::COIN_2_0|SoNode::COIN_2_2|SoNode::COIN_2_3|SoNode::COIN_2_4);

  Py_Initialize();
}

SoPyScript::SoPyScript(void)
  : fielddata(NULL)
{
  this->isBuiltIn = FALSE;
  assert(SoPyScript::classTypeId != SoType::badType());

  this->script.setValue(NULL);
  this->script.setContainer(this);

  if (this->fielddata) delete this->fielddata;
  this->fielddata = new SoFieldData;
  this->fielddata->addField(this, "script", &this->script);

  if (!(thread_state = Py_NewInterpreter())) {
    SoDebugError::postWarning("SoPyScript::initClass",
                              "Creation of new sub-interpreter failed!");
  }

  if (PyRun_SimpleString("from pivy import *")) {
    SoDebugError::postWarning("SoPyScript::initClass",
                              "\n*Yuk!* The box containing a fierce looking python snake to drive\n"
                              "this node has arrived but was found to be empty! The Pivy module\n"
                              "required for the Python Scripting Node could not be successfully\n"
                              "imported! Check your setup and fix it so that the python snake can\n"
                              "happily wiggle and byte you in the ass...");
  }

  PyThreadState * tstate = PyThreadState_Swap((PyThreadState*)thread_state);
  Py_SetProgramName("SoPyScript");
  this->globalModuleDict = PyModule_GetDict(PyImport_AddModule("__main__"));

  /* shovel the the node itself on to the Python interpreter as self instance */
  swig_type_info * swig_type = 0;

  if ((swig_type = SWIG_TypeQuery("SoNode *")) == 0) {
    SoDebugError::post("SoPyScript::SoPyScript",
                       "SoNode type could not be found!");
  }

  /* add the field to the global dict */
  PyDict_SetItemString((PyObject*)this->globalModuleDict,
                       "self",
                       SWIG_NewPointerObj(this, swig_type, 0));

  PyThreadState_Swap(tstate);
}

SoPyScript::~SoPyScript()
{
  Py_EndInterpreter((PyThreadState*)thread_state);

  const int n = this->fielddata->getNumFields();
  for (int i = 0; i < n; i++) {
    SoField * f = this->fielddata->getField(this, i);
    if (f != &this->script) delete f;
  }
  delete this->fielddata;
}

// Doc in parent
SoType
SoPyScript::getClassTypeId(void)
{
  return SoPyScript::classTypeId;
}

// Doc in parent
SoType
SoPyScript::getTypeId(void) const
{
  return SoPyScript::classTypeId;
}

// Doc in parent
void *
SoPyScript::createInstance(void)
{
  return (void*) new SoPyScript;
}

// Doc in parent
const SoFieldData *
SoPyScript::getFieldData(void) const
{
  return this->fielddata;
}

SbBool
SoPyScript::readInstance(SoInput * in, unsigned short flags)
{
  SbString name, typeVal;

  /* read in the first string */
  if (in->read(typeVal) && typeVal == "fields") {
    if (in->read(typeVal) && typeVal == "[") {

      while (in->read(typeVal) && typeVal != "]") {
        SoType type = SoType::fromName(typeVal);

        /* if it denotes a valid type and is derived from SoField then
           read in the next string representing the name of the
           field */
        if (type != SoType::badType() &&
            type.isDerivedFrom(SoField::getClassTypeId()) &&
            in->read(name))
        {
          // check for a comma at the end and strip it off
          const char * fieldname =
            (name[name.getLength()-1] == ',') ? name.getSubString(0, name.getLength()-2).getString() : name.getString();

          /* skip the script field */
          if (!strcmp(fieldname, "script")) { continue; }

          /* instantiate the field and conduct similar actions as the
             SO_NODE_ADD_FIELD macro */
          SoField * field = (SoField *)type.createInstance();
          field->setContainer(this);
          this->fielddata->addField(this, fieldname, field);

          /* shovel the field instance on to the Python interpreter */
          swig_type_info * swig_type = 0;

          /* FIXME: query if the So prefix is needed or not by calling
             the node->getIsBuiltIn() method. 20041012 tamer. */
          typeVal += " *";
          if ((swig_type = SWIG_TypeQuery(typeVal.getString())) == 0) {
            /* FIXME: if soTypeVal is created on the stack, the stack
               gets corrupted. why is this so, by the big fat ass of
               teutates??? 20041012 tamer. */
            /* try again by prefixing the typename with So */
            SbString * soTypeVal = new SbString("So");
            *soTypeVal += typeVal;
            if ((swig_type = SWIG_TypeQuery(soTypeVal->getString())) == 0) {
              SoDebugError::post("SoPyScript::readInstance",
                                 "field type %s unknown!", typeVal.getString());

              return FALSE;
            }
            delete soTypeVal;
          }
          PyThreadState * tstate = PyThreadState_Swap((PyThreadState*)thread_state);

          /* add the field to the global dict */
          PyDict_SetItemString((PyObject*)this->globalModuleDict,
                               fieldname,
                               SWIG_NewPointerObj(field, swig_type, 0));
          PyThreadState_Swap(tstate);
        }
      }
    }
  }

  /* ...and let the regular readInstance() method parse the rest */
  SbBool ok = inherited::readInstance(in, flags);

  PyThreadState * tstate = PyThreadState_Swap((PyThreadState*)thread_state);
  PyRun_SimpleString((char *)script.getValue().getString());
  if (coin_getenv("PIVY_DEBUG")) {
    SoDebugError::postInfo("SoPyScript::readInstance",
                           "script executed at full length!");
  }
  PyThreadState_Swap(tstate);

  return ok;
}

void
SoPyScript::doAction(SoAction * action, const char * funcname)
{
  if (funcname && !script.isIgnored()) {
    PyThreadState * tstate = PyThreadState_Swap((PyThreadState*)thread_state);

    if (coin_getenv("PIVY_DEBUG")) {
      SoDebugError::postInfo("SoPyScript::doAction",
                             "%s called!", action->getTypeId().getName().getString());
      SoDebugError::postInfo("SoPyScript::doAction",
                             "threadstate=%p:%p", tstate, thread_state);
    }

    /* convert the action instance to a Python object */
    swig_type_info * swig_type = 0;

    SbString typeVal(action->getTypeId().getName().getString());

    /* FIXME: query if the So prefix is needed or not by calling
       the node->getIsBuiltIn() method. 20041012 tamer. */
    typeVal += " *";
    if ((swig_type = SWIG_TypeQuery(typeVal.getString())) == 0) {
      /* FIXME: if soTypeVal is created on the stack, the stack gets
         corrupted. why is this so, by the big fat ass of teutates???
         20041012 tamer. */
      /* try again by prefixing the typename with So */
      SbString * soTypeVal = new SbString("So");
      *soTypeVal += typeVal;
      if ((swig_type = SWIG_TypeQuery(soTypeVal->getString())) == 0) {
        SoDebugError::post("SoPyScript::doAction",
                           "%s unknown to Pivy!", typeVal.getString());
      }
      delete soTypeVal;
    }

    if (coin_getenv("PIVY_DEBUG")) {
      SoDebugError::postInfo("SoPyScript::doAction",
                             "typeVal: %s", typeVal.getString());
    }

    PyObject * func = PyDict_GetItemString((PyObject*)this->globalModuleDict, funcname);
    PyObject * pyAction = NULL;

    if (swig_type) {
      pyAction = SWIG_NewPointerObj(action, swig_type, 0);
    }

    PyObject * argtuple = NULL;
    argtuple = Py_BuildValue("(O)", pyAction);

    if (coin_getenv("PIVY_DEBUG")) {
      SoDebugError::postInfo("SoPyScript::doAction",
                             "funcname: %s, func: %p, argtuple: %p",
                             funcname, func, argtuple);
    }

    if (func && argtuple) {
      if (!PyCallable_Check(func)) {
        SbString errMsg(funcname);
        errMsg += " is not a callable object!";
        PyErr_SetString(PyExc_TypeError, errMsg.getString());
      } else {
        PyObject * result;
        if ((result = PyEval_CallObject(func, argtuple)) == NULL) {
          PyErr_Print();
        }
        Py_XDECREF(result);
      }

      Py_DECREF(argtuple);
      Py_DECREF(pyAction);
    }

    // PyRun_SimpleString((char *)script.getValue().getString());
    PyThreadState_Swap(tstate);
  }
  inherited::doAction(action);
}

void
SoPyScript::GLRender(SoGLRenderAction * action)
{
  SoPyScript::doAction(action, "GLRender");
  inherited::GLRender(action);
}

void
SoPyScript::GLRenderBelowPath(SoGLRenderAction * action)
{
  SoPyScript::doAction(action, "GLRenderBelowPath");
  inherited::GLRenderBelowPath(action);
}

void
SoPyScript::GLRenderInPath(SoGLRenderAction * action)
{
  SoPyScript::doAction(action, "GLRenderInPath");
  inherited::GLRenderInPath(action);
}

void
SoPyScript::GLRenderOffPath(SoGLRenderAction * action)
{
  SoPyScript::doAction(action, "GLRenderOffPath");
  inherited::GLRenderOffPath(action);
}

void
SoPyScript::callback(SoCallbackAction * action)
{
  SoPyScript::doAction(action, "callback");
  inherited::callback(action);
}

void
SoPyScript::getBoundingBox(SoGetBoundingBoxAction * action)
{
  SoPyScript::doAction(action, "getBoundingBox");
  inherited::getBoundingBox(action);
}

void
SoPyScript::getMatrix(SoGetMatrixAction * action)
{
  SoPyScript::doAction(action, "getMatrix");
  inherited::getMatrix(action);
}

void
SoPyScript::handleEvent(SoHandleEventAction * action)
{
  SoPyScript::doAction(action, "handleEvent");
  inherited::handleEvent(action);
}

void
SoPyScript::pick(SoPickAction * action)
{
  SoPyScript::doAction(action, "pick");
  inherited::pick(action);
}

void
SoPyScript::rayPick(SoRayPickAction * action)
{
  SoPyScript::doAction(action, "rayPick");
  inherited::rayPick(action);
}

void
SoPyScript::search(SoSearchAction * action)
{
  SoPyScript::doAction(action, "search");
  inherited::search(action);
}

void
SoPyScript::write(SoWriteAction * action)
{
  SoPyScript::doAction(action, "write");
  inherited::write(action);
}

void
SoPyScript::audioRender(SoAudioRenderAction * action)
{
  SoPyScript::doAction(action, "audioRender");
  inherited::audioRender(action);
}

void
SoPyScript::getPrimitiveCount(SoGetPrimitiveCountAction * action)
{
  SoPyScript::doAction(action, "getPrimitiveCount");
  inherited::getPrimitiveCount(action);
}
<|endoftext|>


<commit_before>#include <stdlib.h>
#include <assert.h>
#include <string.h>
#include <math.h>
#include <vector>

#include "HOG.hpp"

#define eps 0.0001

#include <opencv2/core/core.hpp>
#include <opencv2/highgui/highgui.hpp>

using namespace std;
using namespace cv;

static float* compute_HOG(uchar** img, int i, int j){
	float div = 180.0/9.0;
	float* histogram = (float*) malloc(sizeof(float)*(NUM_HIST_BIN+1));
	if( histogram == NULL ){
		printf("ERROR: Unable to allocate cell histogram\n");
		exit(1);
	}
	memset(histogram,0,sizeof(float)*(NUM_HIST_BIN+1));

	for( int k = i; k < i+CELL_HEIGHT; k++){
		for( int l = j; l < j+CELL_WIDTH; l++){

			float dx = (float)( -img[k][l-1]+img[k][l+1] );
			float dy = (float)( -img[k-1][l]+img[k+1][l] );
			float mag = sqrtf( dx*dx + dy*dy + eps );

			dx = dx/mag;
			dy = dy/mag;

			float ang = atan((dx+eps)/(dy+eps));
			ang = M_PI/2.0 + ang;
			ang = ang*(180.0/M_PI);

			int bin = (int)(ang/div);

			assert(bin < NUM_HIST_BIN);

			histogram[bin] += mag;

		}
	}

	for(int k = 0; k < 9; k++){
		histogram[9] += histogram[k];
	}

	return histogram;
}

float** compute_cell_histogram(int top_left_corner_x, int top_left_corner_y, uchar** img, int window_width, int window_height){

	assert( top_left_corner_x > 0);
	assert( top_left_corner_y > 0);

	int cell_x = (window_width)/CELL_WIDTH;
	int cell_y = (window_height)/CELL_HEIGHT;
	float** hist_list = (float**) malloc(sizeof(float**)*cell_x*cell_y);

	int index = 0;

	for( int i = top_left_corner_y; i < top_left_corner_y+(cell_y*CELL_HEIGHT); i+= CELL_HEIGHT) {
		for( int j = top_left_corner_x; j < top_left_corner_x+(cell_x*CELL_WIDTH); j+=CELL_WIDTH) {
			hist_list[index++] = compute_HOG( img, i, j );
		}
	}

	return hist_list;
}

void get_block_vector( vector<float>& features, float** hist_list, int i, int j, int cell_x ){
	float sum_of_squares = 0.0;

	for(int k=0; k < 9; k++){
		features.push_back( hist_list[i*cell_x+j][k] );
		sum_of_squares += features.back()*features.back();
	}
	for(int k=0; k < 9; k++){
		features.push_back( hist_list[i*cell_x+j+1][k] );
		sum_of_squares += features.back()*features.back();
	}
	for(int k=0; k < 9; k++){
		features.push_back( hist_list[(i+1)*cell_x+j][k] );
		sum_of_squares += features.back()*features.back();
	}
	for(int k=0; k < 9; k++){
		features.push_back( hist_list[(i+1)*cell_x+j+1][k] );
		sum_of_squares += features.back()*features.back();
	}

	for( unsigned int k = features.size()-9*4; k < (unsigned int)features.size(); k++) {
		features[k] = features[k]*1.0/sqrtf(sum_of_squares+eps*eps);
	}
}

vector<float> block_normalize(float** hist_list, int cells_x, int cells_y){

	//int num_features = 4*NUM_HIST_BIN*(cells_x-1)*(cells_y-1);
	//float* HOG_features = (float*) malloc( sizeof(float)*num_features );
	//if( HOG_features == NULL ){
	//	printf("ERROR: unable to allocate HOG feature vector\n");
	//	exit(1);
	//}
	//memset(HOG_features, 0, sizeof(float)*num_features);
	vector<float> HOG_features;

	for(int i = 0; i < cells_y-1; i++ ) {
		for( int j = 0; j < cells_x-1; j++) {
			get_block_vector(HOG_features, hist_list, i, j, cells_x);
		}
	}

	return HOG_features;
}

void print_features( vector<float>& features){
	for( unsigned int i = 0; i < (unsigned int)features.size(); i++){
		// Remember: SVM_light feature indices start at 1
		printf("%d:%f ", i+1, features[i]);
	}
	printf("\n");
}

 //float*** compute_sliding_window(uchar** img, int M, int N){
 //
 //	printf("Running a sliding window\n");
 //
 //	assert( M > WIN_HEIGHT );
 //	assert( N > WIN_WIDTH );
 //
 //	int cells_x = WIN_WIDTH/CELL_WIDTH;
 //	int cells_y = WIN_HEIGHT/CELL_HEIGHT;
 //
 //	float*** hist_list = (float***) malloc(sizeof(float***)*cells_x*cells_y);
 //
 //	for(int i = 1; i+WIN_HEIGHT < M; i++ ){
 //		for( int j = 1; j+WIN_WIDTH < N; j++ ){
 //			hist_list[i*cells_x+j] = compute_cell_histogram( j, i, img, WIN_HEIGHT, WIN_WIDTH );
 //		}
 //	}
 //
 //	return hist_list;
 //}

<commit_msg>Changed tan(x/y) -> tan(y/x)<commit_after>#include <stdlib.h>
#include <assert.h>
#include <string.h>
#include <math.h>
#include <vector>

#include "HOG.hpp"

#define eps 0.0001

#include <opencv2/core/core.hpp>
#include <opencv2/highgui/highgui.hpp>

using namespace std;
using namespace cv;

static float* compute_HOG(uchar** img, int i, int j){
	float div = 180.0/9.0;
	float* histogram = (float*) malloc(sizeof(float)*(NUM_HIST_BIN+1));
	if( histogram == NULL ){
		printf("ERROR: Unable to allocate cell histogram\n");
		exit(1);
	}
	memset(histogram,0,sizeof(float)*(NUM_HIST_BIN+1));

	for( int k = i; k < i+CELL_HEIGHT; k++){
		for( int l = j; l < j+CELL_WIDTH; l++){

			float dx = (float)( -img[k][l-1]+img[k][l+1] );
			float dy = (float)( -img[k-1][l]+img[k+1][l] );
			float mag = sqrtf( dx*dx + dy*dy + eps );

			dx = dx/mag;
			dy = dy/mag;

			float ang = atan((dy+eps)/(dx+eps));
			ang = M_PI/2.0 + ang;
			ang = ang*(180.0/M_PI);

			int bin = (int)(ang/div);

			assert(bin < NUM_HIST_BIN);

			histogram[bin] += mag;

		}
	}

	for(int k = 0; k < 9; k++){
		histogram[9] += histogram[k];
	}

	return histogram;
}

float** compute_cell_histogram(int top_left_corner_x, int top_left_corner_y, uchar** img, int window_width, int window_height){

	assert( top_left_corner_x > 0);
	assert( top_left_corner_y > 0);

	int cell_x = (window_width)/CELL_WIDTH;
	int cell_y = (window_height)/CELL_HEIGHT;
	float** hist_list = (float**) malloc(sizeof(float**)*cell_x*cell_y);

	int index = 0;

	for( int i = top_left_corner_y; i < top_left_corner_y+(cell_y*CELL_HEIGHT); i+= CELL_HEIGHT) {
		for( int j = top_left_corner_x; j < top_left_corner_x+(cell_x*CELL_WIDTH); j+=CELL_WIDTH) {
			hist_list[index++] = compute_HOG( img, i, j );
		}
	}

	return hist_list;
}

void get_block_vector( vector<float>& features, float** hist_list, int i, int j, int cell_x ){
	float sum_of_squares = 0.0;

	for(int k=0; k < 9; k++){
		features.push_back( hist_list[i*cell_x+j][k] );
		sum_of_squares += features.back()*features.back();
	}
	for(int k=0; k < 9; k++){
		features.push_back( hist_list[i*cell_x+j+1][k] );
		sum_of_squares += features.back()*features.back();
	}
	for(int k=0; k < 9; k++){
		features.push_back( hist_list[(i+1)*cell_x+j][k] );
		sum_of_squares += features.back()*features.back();
	}
	for(int k=0; k < 9; k++){
		features.push_back( hist_list[(i+1)*cell_x+j+1][k] );
		sum_of_squares += features.back()*features.back();
	}

	for( unsigned int k = features.size()-9*4; k < (unsigned int)features.size(); k++) {
		features[k] = features[k]*1.0/sqrtf(sum_of_squares+eps*eps);
	}
}

vector<float> block_normalize(float** hist_list, int cells_x, int cells_y){

	//int num_features = 4*NUM_HIST_BIN*(cells_x-1)*(cells_y-1);
	//float* HOG_features = (float*) malloc( sizeof(float)*num_features );
	//if( HOG_features == NULL ){
	//	printf("ERROR: unable to allocate HOG feature vector\n");
	//	exit(1);
	//}
	//memset(HOG_features, 0, sizeof(float)*num_features);
	vector<float> HOG_features;

	for(int i = 0; i < cells_y-1; i++ ) {
		for( int j = 0; j < cells_x-1; j++) {
			get_block_vector(HOG_features, hist_list, i, j, cells_x);
		}
	}

	return HOG_features;
}

void print_features( vector<float>& features ){
	for( unsigned int i = 0; i < (unsigned int)features.size(); i++){
		// Remember: SVM_light feature indices start at 1
		printf("%d:%f ", i+1, features[i]);
	}
	printf("\n");
}
void print_features( vector<float>& features, FILE* fp){
	for( unsigned int i = 0; i < (unsigned int)features.size(); i++){
		// Remember: SVM_light feature indices start at 1
		fprintf(fp,"%d:%f ", i+1, features[i]);
	}
	fprintf(fp,"\n");
}

 //float*** compute_sliding_window(uchar** img, int M, int N){
 //
 //	printf("Running a sliding window\n");
 //
 //	assert( M > WIN_HEIGHT );
 //	assert( N > WIN_WIDTH );
 //
 //	int cells_x = WIN_WIDTH/CELL_WIDTH;
 //	int cells_y = WIN_HEIGHT/CELL_HEIGHT;
 //
 //	float*** hist_list = (float***) malloc(sizeof(float***)*cells_x*cells_y);
 //
 //	for(int i = 1; i+WIN_HEIGHT < M; i++ ){
 //		for( int j = 1; j+WIN_WIDTH < N; j++ ){
 //			hist_list[i*cells_x+j] = compute_cell_histogram( j, i, img, WIN_HEIGHT, WIN_WIDTH );
 //		}
 //	}
 //
 //	return hist_list;
 //}

<|endoftext|>