<commit_before>/*=========================================================================

Program:   Medical Imaging & Interaction Toolkit
Module:    $RCSfile$
Language:  C++
Date:      $Date$
Version:   $Revision$

Copyright (c) German Cancer Research Center, Division of Medical and
Biological Informatics. All rights reserved.
See MITKCopyright.txt or http://www.mitk.org/copyright.html for details.

This software is distributed WITHOUT ANY WARRANTY; without even
the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
PURPOSE.  See the above copyright notices for more information.

=========================================================================*/

#include "mitkPicFileReader.h"
#include <itkImageFileReader.h>

//##ModelId=3E1878400265
void mitk::PicFileReader::GenerateOutputInformation()
{
    mitk::Image::Pointer output = this->GetOutput();

    if ((output->IsInitialized()) && (this->GetMTime() <= m_ReadHeaderTime.GetMTime()))
        return;

    itkDebugMacro(<<"Reading file for GenerateOutputInformation()" << m_FileName);

    // Check to see if we can read the file given the name or prefix
    //
    if ( m_FileName == "" && m_FilePrefix == "" )
    {
        throw itk::ImageFileReaderException(__FILE__, __LINE__, "One of FileName or FilePrefix must be non-empty");
    }

    if( m_FileName != "")
    {
        ipPicDescriptor* header=ipPicGetHeader(const_cast<char *>(m_FileName.c_str()), NULL);

        header=ipPicGetTags(const_cast<char *>(m_FileName.c_str()), header);

        if( header == NULL)
        {
            itk::ImageFileReaderException e(__FILE__, __LINE__);
            itk::OStringStream msg;
            msg << " Could not read file "
                << m_FileName.c_str();
            e.SetDescription(msg.str().c_str());
            throw e;
            return;
        }

        output->Initialize(header);
    }
    else
    {
        int numberOfImages=0;
        m_StartFileIndex=0;

        ipPicDescriptor* header=NULL;

        char fullName[1024];

        while(m_StartFileIndex<10)
        {
            sprintf(fullName, m_FilePattern.c_str(), m_FilePrefix.c_str(), m_StartFileIndex+numberOfImages);
            FILE * f=fopen(fullName,"r");
            if(f==NULL)
            {
                //already found an image?
                if(numberOfImages>0)
                    break;
                //no? let's increase start
                ++m_StartFileIndex;
            }
            else
            {
                fclose(f);
                //only open the header of the first file found,
                //@warning what to do when images do not have the same size??
                if(header==NULL)
                {
                    header=ipPicGetHeader(fullName, NULL);
                    header=ipPicGetTags(fullName, header);
                }
                ++numberOfImages;
            }
        }

        printf("\n numberofimages %d\n",numberOfImages);

        if(numberOfImages==0)
        {
            itk::ImageFileReaderException e(__FILE__, __LINE__);
            itk::OStringStream msg;
            msg << "no images found";
            e.SetDescription(msg.str().c_str());
            throw e;
            return;
        }

        //@FIXME: was ist, wenn die Bilder nicht alle gleich gross sind?
        if(numberOfImages>1)
        {
            printf("\n numberofimages %d > 1\n",numberOfImages);
            header->dim=3;
            header->n[2]=numberOfImages;
        }

        printf(" \ninitialisize output\n");
        output->Initialize(header);
    }

    m_ReadHeaderTime.Modified();
}

void mitk::PicFileReader::ConvertHandedness(ipPicDescriptor* pic)
{
  //left to right handed conversion
  if(pic->dim>=3)
  {
      ipPicDescriptor* slice=ipPicCopyHeader(pic, NULL);
      slice->dim=2;
      int size=_ipPicSize(slice);
      slice->data=malloc(size);

      int v, volumes = (pic->dim>3? pic->n[3] : 1);
      int volume_size = size*pic->n[2];

      for(v=0; v<volumes; ++v)
      {
        unsigned char *p_first=(unsigned char *)pic->data;
        unsigned char *p_last=(unsigned char *)pic->data;
        p_first+=v*volume_size;
        p_last+=size*(pic->n[2]-1)+v*volume_size;

        int i, smid=pic->n[2]/2;
        for(i=0; i<smid;++i,p_last-=size, p_first+=size)
        {
            memcpy(slice->data, p_last, size);
            memcpy(p_last, p_first, size);
            memcpy(p_first, slice->data, size);
        }
      }
      ipPicFree(slice);
  }
}

//##ModelId=3E187255016C
void mitk::PicFileReader::GenerateData()
{
    mitk::Image::Pointer output = this->GetOutput();

    // Check to see if we can read the file given the name or prefix
    //
    if ( m_FileName == "" && m_FilePrefix == "" )
    {
        throw itk::ImageFileReaderException(__FILE__, __LINE__, "One of FileName or FilePrefix must be non-empty");
    }

    if( m_FileName != "")
    {
        ipPicDescriptor* pic=ipPicGet(const_cast<char *>(m_FileName.c_str()), NULL);
        ConvertHandedness(pic);
        output->SetPicChannel(pic);

        //slice-wise reading
        //currently much too slow.
        //else
        //{
        //  int sstart, smax;
        //  int tstart, tmax;

        //  sstart=output->GetRequestedRegion().GetIndex(2);
        //  smax=sstart+output->GetRequestedRegion().GetSize(2);

        //  tstart=output->GetRequestedRegion().GetIndex(3);
        //  tmax=tstart+output->GetRequestedRegion().GetSize(3);

        //  int s,t;
        //  for(s=sstart; s<smax; ++s)
        //  {
        //    for(t=tstart; t<tmax; ++t)
        //    {
        //      ipPicDescriptor* pic=ipPicGetSlice(const_cast<char *>(m_FileName.c_str()), NULL, t*smax+s+1);
        //      output->SetPicSlice(pic,s,t);
        //    }
        //  }
        //}
    }
    else
    {
        int position;
        ipPicDescriptor*  pic=NULL;

        int zDim=(output->GetDimension()>2?output->GetDimensions()[2]:1);
        printf("\n zdim is %u \n",zDim);

        for (position = 0; position < zDim; ++position)
        {
            char fullName[1024];

            sprintf(fullName, m_FilePattern.c_str(), m_FilePrefix.c_str(), m_StartFileIndex+position);

            pic=ipPicGet(fullName, pic);
            if(pic==NULL)
            {
                itkDebugMacro("Pic file '" << fullName << "' does not exist.");
            }
            else
            if(output->SetPicSlice(pic, position)==false)
            {
                itkDebugMacro("Image '" << fullName << "' could not be added to Image.");
            }
        }
    }
}

void mitk::PicFileReader::EnlargeOutputRequestedRegion(itk::DataObject *output)
{
  output->SetRequestedRegionToLargestPossibleRegion();
}

//##ModelId=3E1874D202D0
mitk::PicFileReader::PicFileReader()
    : m_FileName(""), m_FilePrefix(""), m_FilePattern("")
{
}

//##ModelId=3E1874E50179
mitk::PicFileReader::~PicFileReader()
{
}
<commit_msg>FIX: free memory in no longer used ipPicDescriptor<commit_after>/*=========================================================================

Program:   Medical Imaging & Interaction Toolkit
Module:    $RCSfile$
Language:  C++
Date:      $Date$
Version:   $Revision$

Copyright (c) German Cancer Research Center, Division of Medical and
Biological Informatics. All rights reserved.
See MITKCopyright.txt or http://www.mitk.org/copyright.html for details.

This software is distributed WITHOUT ANY WARRANTY; without even
the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
PURPOSE.  See the above copyright notices for more information.

=========================================================================*/

#include "mitkPicFileReader.h"
#include <itkImageFileReader.h>

//##ModelId=3E1878400265
void mitk::PicFileReader::GenerateOutputInformation()
{
    mitk::Image::Pointer output = this->GetOutput();

    if ((output->IsInitialized()) && (this->GetMTime() <= m_ReadHeaderTime.GetMTime()))
        return;

    itkDebugMacro(<<"Reading file for GenerateOutputInformation()" << m_FileName);

    // Check to see if we can read the file given the name or prefix
    //
    if ( m_FileName == "" && m_FilePrefix == "" )
    {
        throw itk::ImageFileReaderException(__FILE__, __LINE__, "One of FileName or FilePrefix must be non-empty");
    }

    if( m_FileName != "")
    {
        ipPicDescriptor* header=ipPicGetHeader(const_cast<char *>(m_FileName.c_str()), NULL);

        header=ipPicGetTags(const_cast<char *>(m_FileName.c_str()), header);

        if( header == NULL)
        {
            itk::ImageFileReaderException e(__FILE__, __LINE__);
            itk::OStringStream msg;
            msg << " Could not read file "
                << m_FileName.c_str();
            e.SetDescription(msg.str().c_str());
            throw e;
            return;
        }

        output->Initialize(header);
    }
    else
    {
        int numberOfImages=0;
        m_StartFileIndex=0;

        ipPicDescriptor* header=NULL;

        char fullName[1024];

        while(m_StartFileIndex<10)
        {
            sprintf(fullName, m_FilePattern.c_str(), m_FilePrefix.c_str(), m_StartFileIndex+numberOfImages);
            FILE * f=fopen(fullName,"r");
            if(f==NULL)
            {
                //already found an image?
                if(numberOfImages>0)
                    break;
                //no? let's increase start
                ++m_StartFileIndex;
            }
            else
            {
                fclose(f);
                //only open the header of the first file found,
                //@warning what to do when images do not have the same size??
                if(header==NULL)
                {
                    header=ipPicGetHeader(fullName, NULL);
                    header=ipPicGetTags(fullName, header);
                }
                ++numberOfImages;
            }
        }

        printf("\n numberofimages %d\n",numberOfImages);

        if(numberOfImages==0)
        {
            itk::ImageFileReaderException e(__FILE__, __LINE__);
            itk::OStringStream msg;
            msg << "no images found";
            e.SetDescription(msg.str().c_str());
            throw e;
            return;
        }

        //@FIXME: was ist, wenn die Bilder nicht alle gleich gross sind?
        if(numberOfImages>1)
        {
            printf("\n numberofimages %d > 1\n",numberOfImages);
            header->dim=3;
            header->n[2]=numberOfImages;
        }

        printf(" \ninitialisize output\n");
        output->Initialize(header);
    }

    m_ReadHeaderTime.Modified();
}

void mitk::PicFileReader::ConvertHandedness(ipPicDescriptor* pic)
{
  //left to right handed conversion
  if(pic->dim>=3)
  {
      ipPicDescriptor* slice=ipPicCopyHeader(pic, NULL);
      slice->dim=2;
      int size=_ipPicSize(slice);
      slice->data=malloc(size);

      int v, volumes = (pic->dim>3? pic->n[3] : 1);
      int volume_size = size*pic->n[2];

      for(v=0; v<volumes; ++v)
      {
        unsigned char *p_first=(unsigned char *)pic->data;
        unsigned char *p_last=(unsigned char *)pic->data;
        p_first+=v*volume_size;
        p_last+=size*(pic->n[2]-1)+v*volume_size;

        int i, smid=pic->n[2]/2;
        for(i=0; i<smid;++i,p_last-=size, p_first+=size)
        {
            memcpy(slice->data, p_last, size);
            memcpy(p_last, p_first, size);
            memcpy(p_first, slice->data, size);
        }
      }
      ipPicFree(slice);
  }
}

//##ModelId=3E187255016C
void mitk::PicFileReader::GenerateData()
{
    mitk::Image::Pointer output = this->GetOutput();

    // Check to see if we can read the file given the name or prefix
    //
    if ( m_FileName == "" && m_FilePrefix == "" )
    {
        throw itk::ImageFileReaderException(__FILE__, __LINE__, "One of FileName or FilePrefix must be non-empty");
    }

    if( m_FileName != "")
    {
        ipPicDescriptor* pic=ipPicGet(const_cast<char *>(m_FileName.c_str()), NULL);
        ConvertHandedness(pic);
        output->SetPicChannel(pic);
        ipPicFree(pic);

        //slice-wise reading
        //currently much too slow.
        //else
        //{
        //  int sstart, smax;
        //  int tstart, tmax;

        //  sstart=output->GetRequestedRegion().GetIndex(2);
        //  smax=sstart+output->GetRequestedRegion().GetSize(2);

        //  tstart=output->GetRequestedRegion().GetIndex(3);
        //  tmax=tstart+output->GetRequestedRegion().GetSize(3);

        //  int s,t;
        //  for(s=sstart; s<smax; ++s)
        //  {
        //    for(t=tstart; t<tmax; ++t)
        //    {
        //      ipPicDescriptor* pic=ipPicGetSlice(const_cast<char *>(m_FileName.c_str()), NULL, t*smax+s+1);
        //      output->SetPicSlice(pic,s,t);
        //    }
        //  }
        //}
    }
    else
    {
        int position;
        ipPicDescriptor*  pic=NULL;

        int zDim=(output->GetDimension()>2?output->GetDimensions()[2]:1);
        printf("\n zdim is %u \n",zDim);

        for (position = 0; position < zDim; ++position)
        {
            char fullName[1024];

            sprintf(fullName, m_FilePattern.c_str(), m_FilePrefix.c_str(), m_StartFileIndex+position);

            pic=ipPicGet(fullName, pic);
            if(pic==NULL)
            {
                itkDebugMacro("Pic file '" << fullName << "' does not exist.");
            }
            else
            if(output->SetPicSlice(pic, position)==false)
            {
                itkDebugMacro("Image '" << fullName << "' could not be added to Image.");
            }
       }
       if(pic!=NULL)
         ipPicFree(pic);
    }
}

void mitk::PicFileReader::EnlargeOutputRequestedRegion(itk::DataObject *output)
{
  output->SetRequestedRegionToLargestPossibleRegion();
}

//##ModelId=3E1874D202D0
mitk::PicFileReader::PicFileReader()
    : m_FileName(""), m_FilePrefix(""), m_FilePattern("")
{
}

//##ModelId=3E1874E50179
mitk::PicFileReader::~PicFileReader()
{
}
<|endoftext|>


<commit_before>/*
 * Vulkan Samples Kit
 *
 * Copyright (C) 2015 Valve Corporation
 *
 * Permission is hereby granted, free of charge, to any person obtaining a
 * copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation
 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
 * and/or sell copies of the Software, and to permit persons to whom the
 * Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included
 * in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
 * DEALINGS IN THE SOFTWARE.
 */

/*
VULKAN_SAMPLE_SHORT_DESCRIPTION
enumerate physical devices
*/

#include <cassert>
#include <cstdlib>
#include <util_init.hpp>

int main(int argc, char **argv)
{
    struct sample_info info = {};
    init_instance(info, "vulkansamples_enumerate");

    /* VULKAN_KEY_START */

    uint32_t gpu_count = 1;
    VkResult U_ASSERT_ONLY res = vkEnumeratePhysicalDevices(info.inst, &gpu_count, NULL);
    assert(gpu_count);
    info.gpus.resize(gpu_count);
    res = vkEnumeratePhysicalDevices(info.inst, &gpu_count, info.gpus.data());
    assert(!res && gpu_count == 1);

    /* VULKAN_KEY_END */

    vkDestroyInstance(info.inst, NULL);

    return 0;
}
<commit_msg>Enumerate sample needs to allow for >1 GPU<commit_after>/*
 * Vulkan Samples Kit
 *
 * Copyright (C) 2015 Valve Corporation
 *
 * Permission is hereby granted, free of charge, to any person obtaining a
 * copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation
 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
 * and/or sell copies of the Software, and to permit persons to whom the
 * Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included
 * in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
 * DEALINGS IN THE SOFTWARE.
 */

/*
VULKAN_SAMPLE_SHORT_DESCRIPTION
enumerate physical devices
*/

#include <cassert>
#include <cstdlib>
#include <util_init.hpp>

int main(int argc, char **argv)
{
    struct sample_info info = {};
    init_instance(info, "vulkansamples_enumerate");

    /* VULKAN_KEY_START */

    uint32_t gpu_count = 1;
    VkResult U_ASSERT_ONLY res = vkEnumeratePhysicalDevices(info.inst, &gpu_count, NULL);
    assert(gpu_count);
    info.gpus.resize(gpu_count);
    res = vkEnumeratePhysicalDevices(info.inst, &gpu_count, info.gpus.data());
    assert(!res && gpu_count >= 1);

    /* VULKAN_KEY_END */

    vkDestroyInstance(info.inst, NULL);

    return 0;
}
<|endoftext|>


<commit_before>#include "scraper.hpp"

#include <queue>
#include <jsoncpp/json/json.h>
#include <boost/algorithm/string.hpp>

#include <supermarx/util/stubborn.hpp>

namespace supermarx
{

Json::Value parse_json(std::string const& src)
{
	Json::Value root;
	Json::Reader reader;

	if(!reader.parse(src, root, false))
		throw std::runtime_error("Could not parse json feed");

	return root;
}

scraper::scraper(callback_t _callback, unsigned int _ratelimit, bool _cache)
	: callback(_callback)
	, dl("supermarx vladimir/0.1", _ratelimit, _cache ? boost::optional<std::string>("./cache") : boost::none)
{}

void scraper::get_rootmenu(cat_callback_t const& f)
{
	Json::Value root(parse_json(
		stubborn::attempt<std::string>([&]{
			return dl.fetch("https://api-01.cooponline.nl/shopapi/webshopCategory/getMenu");
		})
	));

	for(auto const& cat : root["rootWebshopCategories"])
	{
		category c({cat["id"].asUInt64(), cat["name"].asString(), cat["hasChildren"].asBool()});
		f(c);
	}
}

void scraper::get_submenu(category const& c, cat_callback_t const& f)
{
	std::string uri("https://api-01.cooponline.nl/shopapi/webshopCategory/getMenu?categoryId=");
	uri += boost::lexical_cast<std::string>(c.id);

	Json::Value root(parse_json(
		stubborn::attempt<std::string>([&]{
			return dl.fetch(uri);
		})
	));

	for(auto const& cat : root["childrenWebshopCategories"])
	{
		category c({cat["id"].asUInt64(), cat["name"].asString(), cat["hasChildren"].asBool()});
		f(c);
	}
}

void report_problem_understanding(std::string const& field, std::string const& value, scraper::problems_t& problems)
{
	std::stringstream sstr;
	sstr << "Unclear '" << field << "'' with value '" << value << "'";

	problems.emplace_back(sstr.str());
}

void scraper::process_products(category const& c)
{
	std::vector<std::string> problems;

	std::string uri("https://api-01.cooponline.nl/shopapi/article/list?offset=0&size=10000&webshopCategoryId=");
	uri += boost::lexical_cast<std::string>(c.id);

	Json::Value root(parse_json(
		stubborn::attempt<std::string>([&]{
			return dl.fetch(uri);
		})
	));

	for(auto const& j : root["articles"])
	{
		product p;
		confidence conf = confidence::NEUTRAL;
		datetime retrieved_on = datetime_now();

		p.identifier = j["articleNumber"].asString();

		std::string brand = j["brand"]["name"].asString();
		if(brand == "-------")
			brand = "coop";

		p.name = brand + " " + j["name"].asString();

		// Coop gives names as uppercase strings, which is undesireable.
		boost::algorithm::to_lower(p.name, std::locale("en_US.utf8")); // TODO fix UTF8-handling with ICU or similar.

		p.valid_on = retrieved_on;
		p.discount_amount = 1;

		p.price = j["salePrice"].asFloat()*100.0;
		if(!j["originalPrice"].isNull())
			p.orig_price = j["originalPrice"].asFloat()*100.0;
		else
			p.orig_price = p.price;

		if(j["mixMatched"].asBool())
		{
			std::string type = j["mixMatchButtonType"].asString();
			if(type == "FIXED_PRICE")
			{
				p.price = j["mixMatchDiscount"].asFloat()*100.0;
			}
			else if(type == "QUANTITY_FIXED_PRICE")
			{
				p.discount_amount = j["mixMatchItemQuantity"].asInt();
				p.price = j["mixMatchDiscount"].asFloat()*100.0 / p.discount_amount;
			}
			else if(type == "PERCENT")
			{
				p.discount_amount = j["mixMatchItemQuantity"].asInt();
				p.price *= j["mixMatchDiscount"].asFloat()/100.0;
			}
			else if(type == "TWO_BUY_ONE_PAY")
			{
				p.discount_amount = j["mixMatchItemQuantity"].asInt();
				p.price *= j["mixMatchDiscount"].asFloat()/100.0;
			}
			else if(type == "" && j["mixMatchDiscount"].isInt() && j["mixMatchDiscount"].asInt() == 100)
			{
				// Not actually a discount, bug in Coop's system
			}
			else
			{
				report_problem_understanding("mixMatchButtonType", type, problems);
				conf = confidence::LOW;
			}
		}

		const static std::map<std::string, std::pair<uint64_t, measure>> measure_map({
			{"DOZIJN", {12, measure::UNITS}},
			{"GROS", {144, measure::UNITS}},
			{"MILIGRAM", {1, measure::MILLIGRAMS}},
			{"GRAM", {1000, measure::MILLIGRAMS}},
			{"HECTOGRM", {100000, measure::MILLIGRAMS}},
			{"KILOGRAM", {1000000, measure::MILLIGRAMS}},
			{"TON", {1000000000, measure::MILLIGRAMS}},
			{"POND", {500000, measure::MILLIGRAMS}},
			{"ONS", {100000, measure::MILLIGRAMS}},
			{"MILIMETR", {1, measure::MILLIMETERS}},
			{"CENTIMTR", {10, measure::MILLIMETERS}},
			{"DECIMETR", {100, measure::MILLIMETERS}},
			{"METER", {1000, measure::MILLIMETERS}},
			{"KILOMETR", {1000000, measure::MILLIMETERS}},
			{"MILILITR", {1, measure::MILLILITERS}},
			{"CENTILTR", {10, measure::MILLILITERS}},
			{"DECILITR", {100, measure::MILLILITERS}},
			{"LITER", {1000, measure::MILLILITERS}},
			{"DECALITR", {10000, measure::MILLILITERS}},
			{"HECTOLTR", {100000, measure::MILLILITERS}},
			{"STUK", {1, measure::UNITS}},
			{"Diversen", {1, measure::UNITS}},
			{"PLAK", {1, measure::UNITS}},
			{"PUNT(EN)", {1, measure::UNITS}},
			{"ROL(LEN)", {1, measure::UNITS}}
		});

		p.volume = 1;
		p.volume_measure = measure::UNITS;

		std::string volume_str = j["volume"].asString();
		std::string measure_str = j["volumeMeasure"]["name"].asString();

		auto measure_it = measure_map.find(measure_str);
		if(measure_it != measure_map.end())
		{
			try
			{
				p.volume = boost::lexical_cast<uint64_t>(volume_str) * measure_it->second.first;
				p.volume_measure = measure_it->second.second;
			} catch(boost::bad_lexical_cast e)
			{
				report_problem_understanding("volume", volume_str, problems);
				conf = confidence::LOW;
			}
		}
		else
		{
			report_problem_understanding("volumeMeasure", volume_str, problems);
			conf = confidence::LOW;
		}

		boost::optional<std::string> image_uri;
		if(j["imageId"].isInt())
			image_uri = "https://api-01.cooponline.nl/shopapi/image/A/N/" + boost::lexical_cast<std::string>(j["imageId"].asUInt());

		callback(uri, image_uri, p, retrieved_on, conf, problems);
	}
}

void scraper::scrape()
{
	std::vector<category> todo;

	cat_callback_t cat_f = [&](category const& c) {
		todo.push_back(c);
	};

	get_rootmenu(cat_f);

	while(!todo.empty())
	{
		category c(todo.back());
		todo.pop_back();

		if(c.has_children)
			get_submenu(c, cat_f);

		process_products(c);
	}
}

raw scraper::download_image(const std::string& uri)
{
	std::string buf(dl.fetch(uri));
	return raw(buf.data(), buf.length());
}

}
<commit_msg>Fixed shadowing<commit_after>#include "scraper.hpp"

#include <queue>
#include <jsoncpp/json/json.h>
#include <boost/algorithm/string.hpp>

#include <supermarx/util/stubborn.hpp>

namespace supermarx
{

Json::Value parse_json(std::string const& src)
{
	Json::Value root;
	Json::Reader reader;

	if(!reader.parse(src, root, false))
		throw std::runtime_error("Could not parse json feed");

	return root;
}

scraper::scraper(callback_t _callback, unsigned int _ratelimit, bool _cache)
	: callback(_callback)
	, dl("supermarx vladimir/0.1", _ratelimit, _cache ? boost::optional<std::string>("./cache") : boost::none)
{}

void scraper::get_rootmenu(cat_callback_t const& f)
{
	Json::Value root(parse_json(
		stubborn::attempt<std::string>([&]{
			return dl.fetch("https://api-01.cooponline.nl/shopapi/webshopCategory/getMenu");
		})
	));

	for(auto const& cat : root["rootWebshopCategories"])
	{
		category c({cat["id"].asUInt64(), cat["name"].asString(), cat["hasChildren"].asBool()});
		f(c);
	}
}

void scraper::get_submenu(category const& c_parent, cat_callback_t const& f)
{
	std::string uri("https://api-01.cooponline.nl/shopapi/webshopCategory/getMenu?categoryId=");
	uri += boost::lexical_cast<std::string>(c_parent.id);

	Json::Value root(parse_json(
		stubborn::attempt<std::string>([&]{
			return dl.fetch(uri);
		})
	));

	for(auto const& cat : root["childrenWebshopCategories"])
	{
		category c({cat["id"].asUInt64(), cat["name"].asString(), cat["hasChildren"].asBool()});
		f(c);
	}
}

void report_problem_understanding(std::string const& field, std::string const& value, scraper::problems_t& problems)
{
	std::stringstream sstr;
	sstr << "Unclear '" << field << "'' with value '" << value << "'";

	problems.emplace_back(sstr.str());
}

void scraper::process_products(category const& c)
{
	std::vector<std::string> problems;

	std::string uri("https://api-01.cooponline.nl/shopapi/article/list?offset=0&size=10000&webshopCategoryId=");
	uri += boost::lexical_cast<std::string>(c.id);

	Json::Value root(parse_json(
		stubborn::attempt<std::string>([&]{
			return dl.fetch(uri);
		})
	));

	for(auto const& j : root["articles"])
	{
		product p;
		confidence conf = confidence::NEUTRAL;
		datetime retrieved_on = datetime_now();

		p.identifier = j["articleNumber"].asString();

		std::string brand = j["brand"]["name"].asString();
		if(brand == "-------")
			brand = "coop";

		p.name = brand + " " + j["name"].asString();

		// Coop gives names as uppercase strings, which is undesireable.
		boost::algorithm::to_lower(p.name, std::locale("en_US.utf8")); // TODO fix UTF8-handling with ICU or similar.

		p.valid_on = retrieved_on;
		p.discount_amount = 1;

		p.price = j["salePrice"].asFloat()*100.0;
		if(!j["originalPrice"].isNull())
			p.orig_price = j["originalPrice"].asFloat()*100.0;
		else
			p.orig_price = p.price;

		if(j["mixMatched"].asBool())
		{
			std::string type = j["mixMatchButtonType"].asString();
			if(type == "FIXED_PRICE")
			{
				p.price = j["mixMatchDiscount"].asFloat()*100.0;
			}
			else if(type == "QUANTITY_FIXED_PRICE")
			{
				p.discount_amount = j["mixMatchItemQuantity"].asInt();
				p.price = j["mixMatchDiscount"].asFloat()*100.0 / p.discount_amount;
			}
			else if(type == "PERCENT")
			{
				p.discount_amount = j["mixMatchItemQuantity"].asInt();
				p.price *= j["mixMatchDiscount"].asFloat()/100.0;
			}
			else if(type == "TWO_BUY_ONE_PAY")
			{
				p.discount_amount = j["mixMatchItemQuantity"].asInt();
				p.price *= j["mixMatchDiscount"].asFloat()/100.0;
			}
			else if(type == "" && j["mixMatchDiscount"].isInt() && j["mixMatchDiscount"].asInt() == 100)
			{
				// Not actually a discount, bug in Coop's system
			}
			else
			{
				report_problem_understanding("mixMatchButtonType", type, problems);
				conf = confidence::LOW;
			}
		}

		const static std::map<std::string, std::pair<uint64_t, measure>> measure_map({
			{"DOZIJN", {12, measure::UNITS}},
			{"GROS", {144, measure::UNITS}},
			{"MILIGRAM", {1, measure::MILLIGRAMS}},
			{"GRAM", {1000, measure::MILLIGRAMS}},
			{"HECTOGRM", {100000, measure::MILLIGRAMS}},
			{"KILOGRAM", {1000000, measure::MILLIGRAMS}},
			{"TON", {1000000000, measure::MILLIGRAMS}},
			{"POND", {500000, measure::MILLIGRAMS}},
			{"ONS", {100000, measure::MILLIGRAMS}},
			{"MILIMETR", {1, measure::MILLIMETERS}},
			{"CENTIMTR", {10, measure::MILLIMETERS}},
			{"DECIMETR", {100, measure::MILLIMETERS}},
			{"METER", {1000, measure::MILLIMETERS}},
			{"KILOMETR", {1000000, measure::MILLIMETERS}},
			{"MILILITR", {1, measure::MILLILITERS}},
			{"CENTILTR", {10, measure::MILLILITERS}},
			{"DECILITR", {100, measure::MILLILITERS}},
			{"LITER", {1000, measure::MILLILITERS}},
			{"DECALITR", {10000, measure::MILLILITERS}},
			{"HECTOLTR", {100000, measure::MILLILITERS}},
			{"STUK", {1, measure::UNITS}},
			{"Diversen", {1, measure::UNITS}},
			{"PLAK", {1, measure::UNITS}},
			{"PUNT(EN)", {1, measure::UNITS}},
			{"ROL(LEN)", {1, measure::UNITS}}
		});

		p.volume = 1;
		p.volume_measure = measure::UNITS;

		std::string volume_str = j["volume"].asString();
		std::string measure_str = j["volumeMeasure"]["name"].asString();

		auto measure_it = measure_map.find(measure_str);
		if(measure_it != measure_map.end())
		{
			try
			{
				p.volume = boost::lexical_cast<uint64_t>(volume_str) * measure_it->second.first;
				p.volume_measure = measure_it->second.second;
			} catch(boost::bad_lexical_cast e)
			{
				report_problem_understanding("volume", volume_str, problems);
				conf = confidence::LOW;
			}
		}
		else
		{
			report_problem_understanding("volumeMeasure", volume_str, problems);
			conf = confidence::LOW;
		}

		boost::optional<std::string> image_uri;
		if(j["imageId"].isInt())
			image_uri = "https://api-01.cooponline.nl/shopapi/image/A/N/" + boost::lexical_cast<std::string>(j["imageId"].asUInt());

		callback(uri, image_uri, p, retrieved_on, conf, problems);
	}
}

void scraper::scrape()
{
	std::vector<category> todo;

	cat_callback_t cat_f = [&](category const& c) {
		todo.push_back(c);
	};

	get_rootmenu(cat_f);

	while(!todo.empty())
	{
		category c(todo.back());
		todo.pop_back();

		if(c.has_children)
			get_submenu(c, cat_f);

		process_products(c);
	}
}

raw scraper::download_image(const std::string& uri)
{
	std::string buf(dl.fetch(uri));
	return raw(buf.data(), buf.length());
}

}
<|endoftext|>


<commit_before>#include "include/a_devdiag.h"
#include "include/netstructures.h"

void a_devdiag() {
	pcap_if_t *alldevs;
	char errbuf[PCAP_ERRBUF_SIZE];

	if (pcap_findalldevs(&alldevs, errbuf) == -1) {
		printf("Error in pcap_findalldevs: %s\n", errbuf);
		exit(1);
	}

	int i = 0;
	pcap_if_t *d;
	for (d = alldevs; d; d = d->next) {
		printf("%d. %s", ++i, d->name);
		if (d->description) {
			printf(" (%s)\n", d->description);
		}
	}

	int inum;
	printf("Enter the interface number (1-%d): ", i);
	scanf_s("%d", &inum);

	for (d = alldevs, i = 0; i< inum - 1; d = d->next, i++);

	pcap_t *adhandle;
	if ((adhandle = pcap_open_live(d->name, 65536, 1000, NULL, errbuf)) == NULL) {
		printf("Unable to open the network adapter. %s is not supported by WinPcap\n", d->name);
		pcap_freealldevs(alldevs);
		exit(1);
	}

	if (pcap_datalink(adhandle) != DLT_EN10MB) {
		printf("Not using an ethernet device: output may not always be correct.\n");
	}

	pcap_freealldevs(alldevs);
	printf("Starting active diagnostics...\n");

	pcap_loop(adhandle, INFINITE, a_packethandler, NULL);
}

void a_packethandler(u_char *param, const struct pcap_pkthdr *header, const u_char *pkt_data) {
	struct tm ltime;
	char timestr[16];
	ip_header *ih;
	udp_header *uh;
	u_int ip_len;
	u_short sport, dport;
	time_t local_tv_sec;

	(VOID)(param);

	local_tv_sec = header->ts.tv_sec;
	localtime_s(&ltime, &local_tv_sec);
	strftime(timestr, sizeof(timestr), "%H:%M:%S", &ltime);
	printf("%s,%.6d len:%d  ", timestr, header->ts.tv_usec, header->len);

	ih = (ip_header *)(pkt_data + 14);

	ip_len = (ih->ver_ihl & 0xf) * 4;
	uh = (udp_header *)((u_char *)ih + ip_len);

	sport = ntohs(uh->sport);
	dport = ntohs(uh->dport);

	printf("%d.%d.%d.%d.%d -> %d.%d.%d.%d.%d           \r",
		ih->saddr.byte1,
		ih->saddr.byte2,
		ih->saddr.byte3,
		ih->saddr.byte4,
		sport,
		ih->daddr.byte1,
		ih->daddr.byte2,
		ih->daddr.byte3,
		ih->daddr.byte4,
		dport);
}<commit_msg>Print IP formatting<commit_after>#include "include/a_devdiag.h"
#include "include/netstructures.h"

void a_devdiag() {
	pcap_if_t *alldevs;
	char errbuf[PCAP_ERRBUF_SIZE];

	if (pcap_findalldevs(&alldevs, errbuf) == -1) {
		printf("Error in pcap_findalldevs: %s\n", errbuf);
		exit(1);
	}

	int i = 0;
	pcap_if_t *d;
	for (d = alldevs; d; d = d->next) {
		printf("%d. %s", ++i, d->name);
		if (d->description) {
			printf(" (%s)\n", d->description);
		}
	}

	int inum;
	printf("Enter the interface number (1-%d): ", i);
	scanf_s("%d", &inum);

	for (d = alldevs, i = 0; i< inum - 1; d = d->next, i++);

	pcap_t *adhandle;
	if ((adhandle = pcap_open_live(d->name, 65536, 1000, NULL, errbuf)) == NULL) {
		printf("Unable to open the network adapter. %s is not supported by WinPcap\n", d->name);
		pcap_freealldevs(alldevs);
		exit(1);
	}

	if (pcap_datalink(adhandle) != DLT_EN10MB) {
		printf("Not using an ethernet device: output may not always be correct.\n");
	}

	pcap_freealldevs(alldevs);
	printf("Starting active diagnostics...\n");

	pcap_loop(adhandle, INFINITE, a_packethandler, NULL);
}

void a_packethandler(u_char *param, const struct pcap_pkthdr *header, const u_char *pkt_data) {
	struct tm ltime;
	char timestr[16];
	ip_header *ih;
	udp_header *uh;
	u_int ip_len;
	u_short sport, dport;
	time_t local_tv_sec;

	(VOID)(param);

	local_tv_sec = header->ts.tv_sec;
	localtime_s(&ltime, &local_tv_sec);
	strftime(timestr, sizeof(timestr), "%H:%M:%S", &ltime);
	printf("%s,%.6d len:%d  ", timestr, header->ts.tv_usec, header->len);

	ih = (ip_header *)(pkt_data + 14);

	ip_len = (ih->ver_ihl & 0xf) * 4;
	uh = (udp_header *)((u_char *)ih + ip_len);

	sport = ntohs(uh->sport);
	dport = ntohs(uh->dport);

	printf("%d.%d.%d.%d:%d -> %d.%d.%d.%d:%d           \r",
		ih->saddr.byte1,
		ih->saddr.byte2,
		ih->saddr.byte3,
		ih->saddr.byte4,
		sport,
		ih->daddr.byte1,
		ih->daddr.byte2,
		ih->daddr.byte3,
		ih->daddr.byte4,
		dport);
}<|endoftext|>


<commit_before>/*=========================================================================

  Program:   Visualization Toolkit
  Module:    vtkBooleanTexture.cc
  Language:  C++
  Date:      $Date$
  Version:   $Revision$

Copyright (c) 1993-1995 Ken Martin, Will Schroeder, Bill Lorensen.

This software is copyrighted by Ken Martin, Will Schroeder and Bill Lorensen.
The following terms apply to all files associated with the software unless
explicitly disclaimed in individual files. This copyright specifically does
not apply to the related textbook "The Visualization Toolkit" ISBN
013199837-4 published by Prentice Hall which is covered by its own copyright.

The authors hereby grant permission to use, copy, and distribute this
software and its documentation for any purpose, provided that existing
copyright notices are retained in all copies and that this notice is included
verbatim in any distributions. Additionally, the authors grant permission to
modify this software and its documentation for any purpose, provided that
such modifications are not distributed without the explicit consent of the
authors and that existing copyright notices are retained in all copies. Some
of the algorithms implemented by this software are patented, observe all
applicable patent law.

IN NO EVENT SHALL THE AUTHORS OR DISTRIBUTORS BE LIABLE TO ANY PARTY FOR
DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT
OF THE USE OF THIS SOFTWARE, ITS DOCUMENTATION, OR ANY DERIVATIVES THEREOF,
EVEN IF THE AUTHORS HAVE BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

THE AUTHORS AND DISTRIBUTORS SPECIFICALLY DISCLAIM ANY WARRANTIES, INCLUDING,
BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
PARTICULAR PURPOSE, AND NON-INFRINGEMENT.  THIS SOFTWARE IS PROVIDED ON AN
"AS IS" BASIS, AND THE AUTHORS AND DISTRIBUTORS HAVE NO OBLIGATION TO PROVIDE
MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.

=========================================================================*/
#include "vtkBooleanTexture.hh"
#include "vtkAGraymap.hh"

vtkBooleanTexture::vtkBooleanTexture()
{
  this->Thickness = 0;

  this->XSize = this->YSize = 12;

  this->InIn[0] = this->InIn[1] = 255;
  this->InOut[0] = this->InOut[1] = 255;
  this->OutIn[0] = this->OutIn[1] = 255;
  this->OutOut[0] = this->OutOut[1] = 255;
  this->OnOn[0] = this->OnOn[1] = 255;
  this->OnIn[0] = this->OnIn[1] = 255;
  this->OnOut[0] = this->OnOut[1] = 255;
  this->InOn[0] = this->InOn[1] = 255;
  this->OutOn[0] = this->OutOn[1] = 255;
}

void vtkBooleanTexture::Execute()
{
  int numPts, i, j;
  vtkAGraymap *newScalars;
  int midILower, midJLower, midIUpper, midJUpper;
  vtkStructuredPoints *output = this->GetOutput();

  if ( (numPts = this->XSize * this->YSize) < 1 )
    {
    vtkErrorMacro(<<"Bad texture (xsize,ysize) specification!");
    return;
    }

  output->SetDimensions(this->XSize,this->YSize,1);
  newScalars = new vtkAGraymap(numPts);
//
// Compute size of various regions
//
  midILower = (int) ((float)(this->XSize - 1) / 2.0 - this->Thickness / 2.0);
  midJLower = (int) ((float)(this->YSize - 1) / 2.0 - this->Thickness / 2.0);
  midIUpper = (int) ((float)(this->XSize - 1) / 2.0 + this->Thickness / 2.0);
  midJUpper = (int) ((float)(this->YSize - 1) / 2.0 + this->Thickness / 2.0);
//
// Create texture map
//
  for (j = 0; j < this->YSize; j++)
    {
    for (i = 0; i < this->XSize; i++)
      {
      if (i < midILower && j < midJLower)
        newScalars->InsertNextColor((unsigned char *)this->InIn);
      else if (i > midIUpper && j < midJLower)
        newScalars->InsertNextColor((unsigned char *)this->OutIn);
      else if (i < midILower && j > midJUpper)
        newScalars->InsertNextColor((unsigned char *)this->InOut);
      else if (i > midIUpper && j > midJUpper)
        newScalars->InsertNextColor((unsigned char *)this->OutOut);
      else if ((i >= midILower && i <= midIUpper) && (j >= midJLower && j <= midJUpper))
        newScalars->InsertNextColor((unsigned char *)this->OnOn);
      else if ((i >= midILower && i <= midIUpper) && j < midJLower)
        newScalars->InsertNextColor((unsigned char *)this->OnIn);
      else if ((i >= midILower && i <= midIUpper) && j > midJUpper)
        newScalars->InsertNextColor((unsigned char *)this->OnOut);
      else if (i < midILower && (j >= midJLower && j <= midJUpper))
        newScalars->InsertNextColor((unsigned char *)this->InOn);
      else if (i > midIUpper && (j >= midJLower && j <= midJUpper))
        newScalars->InsertNextColor((unsigned char *)this->OutOn);
      }
    }

//
// Update ourselves
//
  output->GetPointData()->SetScalars(newScalars);
  newScalars->Delete();
}

void vtkBooleanTexture::PrintSelf(ostream& os, vtkIndent indent)
{
  vtkStructuredPointsSource::PrintSelf(os,indent);

  os << indent << "Thickness: " << this->Thickness << "\n";
  os << indent << "In/In: (" << this->InIn[0] << "," << this->InIn[1] << ")\n";
  os << indent << "In/Out: (" << this->InOut[0] << "," << this->InOut[1] << ")\n";
  os << indent << "Out/In: (" << this->OutIn[0] << "," << this->OutIn[1] << ")\n";
  os << indent << "Out/Out: (" << this->OutOut[0] << "," << this->OutOut[1] << ")\n";
  os << indent << "On/On: (" << this->OnOn[0] << "," << this->OnOn[1] << ")\n";
  os << indent << "On/In: (" << this->OnIn[0] << "," << this->OnIn[1] << ")\n";
  os << indent << "On/Out: (" << this->OnOut[0] << "," << this->OnOut[1] << ")\n";
  os << indent << "In/On: (" << this->InOn[0] << "," << this->InOn[1] << ")\n";
  os << indent << "Out/On: (" << this->OutOn[0] << "," << this->OutOn[1] << ")\n";
}

<commit_msg>ERR: was not passing in rgba to AGrayMap.<commit_after>/*=========================================================================

  Program:   Visualization Toolkit
  Module:    vtkBooleanTexture.cc
  Language:  C++
  Date:      $Date$
  Version:   $Revision$

Copyright (c) 1993-1995 Ken Martin, Will Schroeder, Bill Lorensen.

This software is copyrighted by Ken Martin, Will Schroeder and Bill Lorensen.
The following terms apply to all files associated with the software unless
explicitly disclaimed in individual files. This copyright specifically does
not apply to the related textbook "The Visualization Toolkit" ISBN
013199837-4 published by Prentice Hall which is covered by its own copyright.

The authors hereby grant permission to use, copy, and distribute this
software and its documentation for any purpose, provided that existing
copyright notices are retained in all copies and that this notice is included
verbatim in any distributions. Additionally, the authors grant permission to
modify this software and its documentation for any purpose, provided that
such modifications are not distributed without the explicit consent of the
authors and that existing copyright notices are retained in all copies. Some
of the algorithms implemented by this software are patented, observe all
applicable patent law.

IN NO EVENT SHALL THE AUTHORS OR DISTRIBUTORS BE LIABLE TO ANY PARTY FOR
DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT
OF THE USE OF THIS SOFTWARE, ITS DOCUMENTATION, OR ANY DERIVATIVES THEREOF,
EVEN IF THE AUTHORS HAVE BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

THE AUTHORS AND DISTRIBUTORS SPECIFICALLY DISCLAIM ANY WARRANTIES, INCLUDING,
BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
PARTICULAR PURPOSE, AND NON-INFRINGEMENT.  THIS SOFTWARE IS PROVIDED ON AN
"AS IS" BASIS, AND THE AUTHORS AND DISTRIBUTORS HAVE NO OBLIGATION TO PROVIDE
MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.

=========================================================================*/
#include "vtkBooleanTexture.hh"
#include "vtkAGraymap.hh"

vtkBooleanTexture::vtkBooleanTexture()
{
  this->Thickness = 0;

  this->XSize = this->YSize = 12;

  this->InIn[0] = this->InIn[1] = 255;
  this->InOut[0] = this->InOut[1] = 255;
  this->OutIn[0] = this->OutIn[1] = 255;
  this->OutOut[0] = this->OutOut[1] = 255;
  this->OnOn[0] = this->OnOn[1] = 255;
  this->OnIn[0] = this->OnIn[1] = 255;
  this->OnOut[0] = this->OnOut[1] = 255;
  this->InOn[0] = this->InOn[1] = 255;
  this->OutOn[0] = this->OutOn[1] = 255;
}

void vtkBooleanTexture::Execute()
{
  unsigned char _InIn[4];
  unsigned char _InOut[4];
  unsigned char _OutIn[4];
  unsigned char _OutOut[4];
  unsigned char _OnOn[4];
  unsigned char _OnIn[4];
  unsigned char _OnOut[4];
  unsigned char _InOn[4];
  unsigned char _OutOn[4];
  int numPts, i, j;
  vtkAGraymap *newScalars;
  int midILower, midJLower, midIUpper, midJUpper;
  vtkStructuredPoints *output = this->GetOutput();

  if ( (numPts = this->XSize * this->YSize) < 1 )
    {
    vtkErrorMacro(<<"Bad texture (xsize,ysize) specification!");
    return;
    }

  output->SetDimensions(this->XSize,this->YSize,1);
  newScalars = new vtkAGraymap(numPts);
//
// Compute size of various regions
//
  midILower = (int) ((float)(this->XSize - 1) / 2.0 - this->Thickness / 2.0);
  midJLower = (int) ((float)(this->YSize - 1) / 2.0 - this->Thickness / 2.0);
  midIUpper = (int) ((float)(this->XSize - 1) / 2.0 + this->Thickness / 2.0);
  midJUpper = (int) ((float)(this->YSize - 1) / 2.0 + this->Thickness / 2.0);
//
// Convert intesity, alpha to rgba
//
  _InIn[0] = _InIn[1] = _InIn[2] = this->InIn[1];
  _InIn[3] = this->InIn[0];
  _InOut[0] = _InOut[1] = _InOut[2] = this->InOut[1];
  _InOut[3] = this->InOut[0];
  _OutIn[0] = _OutIn[1] = _OutIn[2] = this->OutIn[1];
  _OutIn[3] = this->OutIn[0];
  _OutOut[0] = _OutOut[1] = _OutOut[2] = this->OutOut[1];
  _OutOut[3] = this->OutOut[0];
  _OnOn[0] = _OnOn[1] = _OnOn[2] = this->OnOn[1];
  _OnOn[3] = this->OnOn[0];
  _OnIn[0] = _OnIn[1] = _OnIn[2] = this->OnIn[1];
  _OnIn[3] = this->OnIn[0];
  _OnOut[0] = _OnOut[1] = _OnOut[2] = this->OnOut[1];
  _OnOut[3] = this->OnOut[0];
  _InOn[0] = _InOn[1] = _InOn[2] = this->InOn[1];
  _InOn[3] = this->InOn[0];
  _OutOn[0] = _OutOn[1] = _OutOn[2] = this->OutOn[1];
  _OutOn[3] = this->OutOn[0];

//
// Create texture map
//
  for (j = 0; j < this->YSize; j++)
    {
    for (i = 0; i < this->XSize; i++)
      {
      if (i < midILower && j < midJLower)
        newScalars->InsertNextColor((unsigned char *)_InIn);
      else if (i > midIUpper && j < midJLower)
        newScalars->InsertNextColor((unsigned char *)_OutIn);
      else if (i < midILower && j > midJUpper)
        newScalars->InsertNextColor((unsigned char *)_InOut);
      else if (i > midIUpper && j > midJUpper)
        newScalars->InsertNextColor((unsigned char *)_OutOut);
      else if ((i >= midILower && i <= midIUpper) && (j >= midJLower && j <= midJUpper))
        newScalars->InsertNextColor((unsigned char *)_OnOn);
      else if ((i >= midILower && i <= midIUpper) && j < midJLower)
        newScalars->InsertNextColor((unsigned char *)_OnIn);
      else if ((i >= midILower && i <= midIUpper) && j > midJUpper)
        newScalars->InsertNextColor((unsigned char *)_OnOut);
      else if (i < midILower && (j >= midJLower && j <= midJUpper))
        newScalars->InsertNextColor((unsigned char *)_InOn);
      else if (i > midIUpper && (j >= midJLower && j <= midJUpper))
        newScalars->InsertNextColor((unsigned char *)_OutOn);
      }
    }

//
// Update ourselves
//
  output->GetPointData()->SetScalars(newScalars);
  newScalars->Delete();
}

void vtkBooleanTexture::PrintSelf(ostream& os, vtkIndent indent)
{
  vtkStructuredPointsSource::PrintSelf(os,indent);

  os << indent << "Thickness: " << this->Thickness << "\n";
  os << indent << "In/In: (" << this->InIn[0] << "," << this->InIn[1] << ")\n";
  os << indent << "In/Out: (" << this->InOut[0] << "," << this->InOut[1] << ")\n";
  os << indent << "Out/In: (" << this->OutIn[0] << "," << this->OutIn[1] << ")\n";
  os << indent << "Out/Out: (" << this->OutOut[0] << "," << this->OutOut[1] << ")\n";
  os << indent << "On/On: (" << this->OnOn[0] << "," << this->OnOn[1] << ")\n";
  os << indent << "On/In: (" << this->OnIn[0] << "," << this->OnIn[1] << ")\n";
  os << indent << "On/Out: (" << this->OnOut[0] << "," << this->OnOut[1] << ")\n";
  os << indent << "In/On: (" << this->InOn[0] << "," << this->InOn[1] << ")\n";
  os << indent << "Out/On: (" << this->OutOn[0] << "," << this->OutOn[1] << ")\n";
}

<|endoftext|>


<commit_before>#include <cvd/glwindow.h>
#include <exception>

#include <X11/Xlib.h>
#include <X11/keysym.h>
#include <GL/glx.h>

using namespace CVD;

CVD::Exceptions::GLWindow::CreationError::CreationError(std::string w)
{
    what="GLWindow creation error: " + w;
}

CVD::Exceptions::GLWindow::RuntimeError::RuntimeError(std::string w)
{
    what="GLWindow error: " + w;
}

struct GLWindow::State {
    ImageRef size;
    std::string title;
    Display* display;
    Window window;
    Atom delete_atom;
    Cursor null_cursor;
    GLXContext context;
};

void CVD::GLWindow::init(const ImageRef& size, int bpp, const std::string& title)
{
    Display* display = XOpenDisplay(0);
    if (display == 0)
	throw Exceptions::GLWindow::CreationError("Cannot open X display");

    int visualAttributes[] = {
	GLX_RGBA,
	GLX_DOUBLEBUFFER,
	GLX_RED_SIZE,      bpp/3,
	GLX_GREEN_SIZE,    bpp/3,
	GLX_BLUE_SIZE,     bpp/3,
	GLX_DEPTH_SIZE,    8,
	None
    };
    XVisualInfo* visualInfo = glXChooseVisual(display, DefaultScreen(display),visualAttributes);
    if(visualAttributes == 0) {
	XCloseDisplay(display);
	throw Exceptions::GLWindow::CreationError("glXChooseVisual failed");
    }

    Window rootWindow = RootWindow(display, visualInfo->screen);
    XWindowAttributes windowAttributes;

    XGetWindowAttributes(display, rootWindow, &windowAttributes);

    XSetWindowAttributes attributes;
    attributes.border_pixel = 0;
    attributes.colormap = XCreateColormap(display, rootWindow, visualInfo->visual, AllocNone);
    attributes.event_mask = KeyPressMask | KeyReleaseMask | ButtonPressMask | ButtonReleaseMask | PointerMotionMask | StructureNotifyMask | ExposureMask;

    Window window = XCreateWindow(display,
				  rootWindow,
				  0, 0, size.x, size.y,
				  0, visualInfo->depth,
				  InputOutput,
				  visualInfo->visual,
				  CWBorderPixel | CWColormap | CWEventMask,
				  &attributes);
    XStoreName(display, window, title.c_str());
    XMapWindow(display, window);
    XEvent ev;
    do {
        XNextEvent(display,&ev);
    } while (ev.type != MapNotify);

    Atom delete_atom = XInternAtom(display, "WM_DELETE_WINDOW", True);
    XSetWMProtocols(display, window, &delete_atom, 1);

    GLXContext context = glXCreateContext(display, visualInfo, 0, True);
    if (context == 0) {
	XDestroyWindow(display, window);
	XCloseDisplay(display);
	throw Exceptions::GLWindow::CreationError("glXCreateContext failed");
    }

    if (glXMakeCurrent(display, window, context) == False) {
	glXDestroyContext(display, context);
	XDestroyWindow(display, window);
	XCloseDisplay(display);
	throw Exceptions::GLWindow::CreationError("glXMakeCurrent failed");
    }
    glLoadIdentity();
    glViewport(0, 0, size.x, size.y);
    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();
    glColor3f(1.0f,1.0f,1.0f);
    glRasterPos2f(-1, 1);
    glOrtho(0, size.x, size.y, 0, -1 , 1);
    glPixelZoom(1,-1);

    XColor black = {0, 0, 0, 0, 0, 0};
    XFontStruct* fixed = XLoadQueryFont(display, "-misc-fixed-medium-r-*-*-12-*-*-*-*-*-*-1" );
    Cursor null_cursor = XCreateGlyphCursor(display, fixed->fid, fixed->fid, ' ', ' ', &black, &black);
    XFreeFont(display, fixed);

    state = new State();
    state->size = size;
    state->title = title;
    state->display = display;
    state->window = window;
    state->delete_atom = delete_atom;
    state->null_cursor = null_cursor;
    state->context = context;
}

CVD::GLWindow::~GLWindow()
{
    glXMakeCurrent(state->display, None, 0);
    glXDestroyContext(state->display, state->context);

    XUnmapWindow(state->display, state->window);
    XDestroyWindow(state->display, state->window);
    XCloseDisplay(state->display);
    delete state;
}

ImageRef CVD::GLWindow::size() const { return state->size; }

void CVD::GLWindow::set_cursor_position(const ImageRef& where)
{
    XWarpPointer(state->display, None, state->window, 0, 0, 0, 0, where.x, where.y);
}

ImageRef CVD::GLWindow::cursor_position() const
{
    Window wtmp;
    int itmp;
    unsigned int utmp;
    ImageRef where;
    XQueryPointer(state->display, state->window, &wtmp, &wtmp, &itmp, &itmp, &where.x, &where.y, &utmp);
    return where;
}

void CVD::GLWindow::show_cursor(bool show)
{
    if (show)
	XUndefineCursor(state->display, state->window);
    else
	XDefineCursor(state->display, state->window, state->null_cursor);
}

std::string CVD::GLWindow::title() const
{
    return state->title;
}

void CVD::GLWindow::set_title(const std::string& title)
{
    state->title = title;
    XStoreName(state->display, state->window, title.c_str());
}

void CVD::GLWindow::swap_buffers()
{
    glXSwapBuffers(state->display, state->window);
}

inline int convertButton(unsigned int button)
{
  switch (button) {
  case Button1: return GLWindow::BUTTON_LEFT;
  case Button2: return GLWindow::BUTTON_MIDDLE;
  case Button3: return GLWindow::BUTTON_RIGHT;
  case Button4: return GLWindow::BUTTON_WHEEL_UP;
  case Button5: return GLWindow::BUTTON_WHEEL_DOWN;
  }
  return 0;
}

inline int convertButtonState(unsigned int state)
{
  int ret = 0;
  if (state & Button1Mask) ret |= GLWindow::BUTTON_LEFT;
  if (state & Button2Mask) ret |= GLWindow::BUTTON_MIDDLE;
  if (state & Button3Mask) ret |= GLWindow::BUTTON_RIGHT;
  if (state & ControlMask) ret |= GLWindow::BUTTON_MOD_CTRL;
  if (state & ShiftMask) ret |= GLWindow::BUTTON_MOD_SHIFT;
  return ret;
}

void CVD::GLWindow::handle_events(EventHandler& handler)
{
    XEvent event;
    while (XPending(state->display)) {
	XNextEvent(state->display, &event);
	switch (event.type) {
	case ButtonPress:
	    handler.on_mouse_down(*this, ImageRef(event.xbutton.x, event.xbutton.y),
				  convertButtonState(event.xbutton.state), convertButton(event.xbutton.button));
	    break;
	case ButtonRelease:
	    handler.on_mouse_up(*this, ImageRef(event.xbutton.x, event.xbutton.y),
				convertButtonState(event.xbutton.state), convertButton(event.xbutton.button));
	    break;
	case MotionNotify:
	    handler.on_mouse_move(*this, ImageRef(event.xmotion.x, event.xmotion.y), convertButtonState(event.xbutton.state));
	    break;
	case KeyPress:
	    handler.on_key_down(*this, XLookupKeysym(&event.xkey, 0));
	    break;
	case KeyRelease:
	    handler.on_key_up(*this, XLookupKeysym(&event.xkey, 0));
	    break;
	    //case UnmapNotify: active = 0; break;
	    //case MapNotify: active = 1; break;
	case ConfigureNotify:
	    if (event.xconfigure.width != state->size.x || event.xconfigure.height != state->size.y) {
		activate();
		state->size = ImageRef(event.xconfigure.width & (~0x3), event.xconfigure.height & (~0x3));
		glViewport(0, 0, state->size.x, state->size.y);
		//glRasterPos2f(0,0);
		//glPixelZoom(float(event.xconfigure.width)/myWidth,-float(event.xconfigure.height)/myHeight);
		handler.on_resize(*this, state->size);
	    }
	    break;
	case Expose:
		handler.on_event(*this, EVENT_EXPOSE);
		break;
	case ClientMessage:
	    if (event.xclient.data.l[0] == (int)state->delete_atom)
		handler.on_event(*this, EVENT_CLOSE);
	    else
		handler.on_event(*this, event.xclient.message_type);
	    break;
	default:
	    handler.on_event(*this, event.type);
	    break;
	}
    }
}

class SaveEvents : public GLWindow::EventHandler {
private:
    std::vector<GLWindow::Event>& events;
public:
    SaveEvents(std::vector<GLWindow::Event>& events_) : events(events_) {}
    void on_key_down(GLWindow& win, int key) {
	GLWindow::Event e;
	e.type = GLWindow::Event::KEY_DOWN;
	e.which = key;
	events.push_back(e);
    }
    void on_key_up(GLWindow& win, int key) {
	GLWindow::Event e;
	e.type = GLWindow::Event::KEY_UP;
	e.which = key;
	events.push_back(e);
    }

    void on_mouse_move(GLWindow& win, ImageRef where, int state) {
	GLWindow::Event e;
	e.type = GLWindow::Event::MOUSE_MOVE;
	e.state = state;
	e.where = where;
	events.push_back(e);
    }

    void on_mouse_down(GLWindow& win, ImageRef where, int state, int button) {
	GLWindow::Event e;
	e.type = GLWindow::Event::MOUSE_DOWN;
	e.state = state;
	e.which = button;
	e.where = where;
	events.push_back(e);
    }

    void on_mouse_up(GLWindow& win, ImageRef where, int state, int button) {
	GLWindow::Event e;
	e.type = GLWindow::Event::MOUSE_UP;
	e.state = state;
	e.which = button;
	e.where = where;
	events.push_back(e);
    }

    void on_resize(GLWindow& win, ImageRef size) {
	GLWindow::Event e;
	e.type = GLWindow::Event::RESIZE;
	e.size = size;
	events.push_back(e);
    }

    void on_event(GLWindow& win, int event) {
	GLWindow::Event e;
	e.type = GLWindow::Event::EVENT;
	e.which = event;
	events.push_back(e);
    }
};

void CVD::GLWindow::get_events(std::vector<Event>& events)
{
    SaveEvents saver(events);
    handle_events(saver);
}

bool CVD::GLWindow::EventSummary::should_quit() const
{
    return key_down.count(XK_Escape) || events.count(GLWindow::EVENT_CLOSE);
}

class MakeSummary : public GLWindow::EventHandler {
private:
    GLWindow::EventSummary& summary;
public:
    MakeSummary(GLWindow::EventSummary& summary_) : summary(summary_) {}

    void on_key_down(GLWindow& win, int key) {	++summary.key_down[key]; }
    void on_key_up(GLWindow& win, int key) { ++summary.key_up[key]; }
    void on_mouse_move(GLWindow& win, ImageRef where, int state) { summary.cursor = where; }
    void on_mouse_down(GLWindow& win, ImageRef where, int state, int button) { summary.mouse_down[button] = std::make_pair(where,state); }
    void on_mouse_up(GLWindow& win, ImageRef where, int state, int button) { summary.mouse_up[button] = std::make_pair(where,state); }
    void on_event(GLWindow& win, int event) { ++summary.events[event]; }
};

void GLWindow::get_events(EventSummary& summary)
{
    MakeSummary ms(summary);
    handle_events(ms);
}

bool CVD::GLWindow::has_events() const
{
    return XPending(state->display);
}

void CVD::GLWindow::activate()
{
    if (glXMakeCurrent(state->display, state->window, state->context) == False)
	throw Exceptions::GLWindow::RuntimeError("glXMakeCurrent failed");
}

<commit_msg>XLookupKeySym doesn't deal with modifiers, but XLookupString does.<commit_after>#include <cvd/glwindow.h>
#include <exception>

#include <X11/Xlib.h>
#include <X11/keysym.h>
#include <GL/glx.h>

using namespace CVD;

CVD::Exceptions::GLWindow::CreationError::CreationError(std::string w)
{
    what="GLWindow creation error: " + w;
}

CVD::Exceptions::GLWindow::RuntimeError::RuntimeError(std::string w)
{
    what="GLWindow error: " + w;
}

struct GLWindow::State {
    ImageRef size;
    std::string title;
    Display* display;
    Window window;
    Atom delete_atom;
    Cursor null_cursor;
    GLXContext context;
};

void CVD::GLWindow::init(const ImageRef& size, int bpp, const std::string& title)
{
    Display* display = XOpenDisplay(0);
    if (display == 0)
	throw Exceptions::GLWindow::CreationError("Cannot open X display");

    int visualAttributes[] = {
	GLX_RGBA,
	GLX_DOUBLEBUFFER,
	GLX_RED_SIZE,      bpp/3,
	GLX_GREEN_SIZE,    bpp/3,
	GLX_BLUE_SIZE,     bpp/3,
	GLX_DEPTH_SIZE,    8,
	None
    };
    XVisualInfo* visualInfo = glXChooseVisual(display, DefaultScreen(display),visualAttributes);
    if(visualAttributes == 0) {
	XCloseDisplay(display);
	throw Exceptions::GLWindow::CreationError("glXChooseVisual failed");
    }

    Window rootWindow = RootWindow(display, visualInfo->screen);
    XWindowAttributes windowAttributes;

    XGetWindowAttributes(display, rootWindow, &windowAttributes);

    XSetWindowAttributes attributes;
    attributes.border_pixel = 0;
    attributes.colormap = XCreateColormap(display, rootWindow, visualInfo->visual, AllocNone);
    attributes.event_mask = KeyPressMask | KeyReleaseMask | ButtonPressMask | ButtonReleaseMask | PointerMotionMask | StructureNotifyMask | ExposureMask;

    Window window = XCreateWindow(display,
				  rootWindow,
				  0, 0, size.x, size.y,
				  0, visualInfo->depth,
				  InputOutput,
				  visualInfo->visual,
				  CWBorderPixel | CWColormap | CWEventMask,
				  &attributes);
    XStoreName(display, window, title.c_str());
    XMapWindow(display, window);
    XEvent ev;
    do {
        XNextEvent(display,&ev);
    } while (ev.type != MapNotify);

    Atom delete_atom = XInternAtom(display, "WM_DELETE_WINDOW", True);
    XSetWMProtocols(display, window, &delete_atom, 1);

    GLXContext context = glXCreateContext(display, visualInfo, 0, True);
    if (context == 0) {
	XDestroyWindow(display, window);
	XCloseDisplay(display);
	throw Exceptions::GLWindow::CreationError("glXCreateContext failed");
    }

    if (glXMakeCurrent(display, window, context) == False) {
	glXDestroyContext(display, context);
	XDestroyWindow(display, window);
	XCloseDisplay(display);
	throw Exceptions::GLWindow::CreationError("glXMakeCurrent failed");
    }
    glLoadIdentity();
    glViewport(0, 0, size.x, size.y);
    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();
    glColor3f(1.0f,1.0f,1.0f);
    glRasterPos2f(-1, 1);
    glOrtho(0, size.x, size.y, 0, -1 , 1);
    glPixelZoom(1,-1);

    XColor black = {0, 0, 0, 0, 0, 0};
    XFontStruct* fixed = XLoadQueryFont(display, "-misc-fixed-medium-r-*-*-12-*-*-*-*-*-*-1" );
    Cursor null_cursor = XCreateGlyphCursor(display, fixed->fid, fixed->fid, ' ', ' ', &black, &black);
    XFreeFont(display, fixed);

    state = new State();
    state->size = size;
    state->title = title;
    state->display = display;
    state->window = window;
    state->delete_atom = delete_atom;
    state->null_cursor = null_cursor;
    state->context = context;
}

CVD::GLWindow::~GLWindow()
{
    glXMakeCurrent(state->display, None, 0);
    glXDestroyContext(state->display, state->context);

    XUnmapWindow(state->display, state->window);
    XDestroyWindow(state->display, state->window);
    XCloseDisplay(state->display);
    delete state;
}

ImageRef CVD::GLWindow::size() const { return state->size; }

void CVD::GLWindow::set_cursor_position(const ImageRef& where)
{
    XWarpPointer(state->display, None, state->window, 0, 0, 0, 0, where.x, where.y);
}

ImageRef CVD::GLWindow::cursor_position() const
{
    Window wtmp;
    int itmp;
    unsigned int utmp;
    ImageRef where;
    XQueryPointer(state->display, state->window, &wtmp, &wtmp, &itmp, &itmp, &where.x, &where.y, &utmp);
    return where;
}

void CVD::GLWindow::show_cursor(bool show)
{
    if (show)
	XUndefineCursor(state->display, state->window);
    else
	XDefineCursor(state->display, state->window, state->null_cursor);
}

std::string CVD::GLWindow::title() const
{
    return state->title;
}

void CVD::GLWindow::set_title(const std::string& title)
{
    state->title = title;
    XStoreName(state->display, state->window, title.c_str());
}

void CVD::GLWindow::swap_buffers()
{
    glXSwapBuffers(state->display, state->window);
}

inline int convertButton(unsigned int button)
{
  switch (button) {
  case Button1: return GLWindow::BUTTON_LEFT;
  case Button2: return GLWindow::BUTTON_MIDDLE;
  case Button3: return GLWindow::BUTTON_RIGHT;
  case Button4: return GLWindow::BUTTON_WHEEL_UP;
  case Button5: return GLWindow::BUTTON_WHEEL_DOWN;
  }
  return 0;
}

inline int convertButtonState(unsigned int state)
{
  int ret = 0;
  if (state & Button1Mask) ret |= GLWindow::BUTTON_LEFT;
  if (state & Button2Mask) ret |= GLWindow::BUTTON_MIDDLE;
  if (state & Button3Mask) ret |= GLWindow::BUTTON_RIGHT;
  if (state & ControlMask) ret |= GLWindow::BUTTON_MOD_CTRL;
  if (state & ShiftMask) ret |= GLWindow::BUTTON_MOD_SHIFT;
  return ret;
}

void CVD::GLWindow::handle_events(EventHandler& handler)
{
    XEvent event;
	KeySym k;
    while (XPending(state->display)) {
	XNextEvent(state->display, &event);
	switch (event.type) {
	case ButtonPress:
	    handler.on_mouse_down(*this, ImageRef(event.xbutton.x, event.xbutton.y),
				  convertButtonState(event.xbutton.state), convertButton(event.xbutton.button));
	    break;
	case ButtonRelease:
	    handler.on_mouse_up(*this, ImageRef(event.xbutton.x, event.xbutton.y),
				convertButtonState(event.xbutton.state), convertButton(event.xbutton.button));
	    break;
	case MotionNotify:
	    handler.on_mouse_move(*this, ImageRef(event.xmotion.x, event.xmotion.y), convertButtonState(event.xbutton.state));
	    break;
	case KeyPress:
		{
		XLookupString(&event.xkey, 0, 0, &k, 0);
	    handler.on_key_down(*this, k);
	    break;
		}
	case KeyRelease:
		XLookupString(&event.xkey, 0, 0, &k, 0);
	    handler.on_key_up(*this, k);
	    break;
	    //case UnmapNotify: active = 0; break;
	    //case MapNotify: active = 1; break;
	case ConfigureNotify:
	    if (event.xconfigure.width != state->size.x || event.xconfigure.height != state->size.y) {
		activate();
		state->size = ImageRef(event.xconfigure.width & (~0x3), event.xconfigure.height & (~0x3));
		glViewport(0, 0, state->size.x, state->size.y);
		//glRasterPos2f(0,0);
		//glPixelZoom(float(event.xconfigure.width)/myWidth,-float(event.xconfigure.height)/myHeight);
		handler.on_resize(*this, state->size);
	    }
	    break;
	case Expose:
		handler.on_event(*this, EVENT_EXPOSE);
		break;
	case ClientMessage:
	    if (event.xclient.data.l[0] == (int)state->delete_atom)
		handler.on_event(*this, EVENT_CLOSE);
	    else
		handler.on_event(*this, event.xclient.message_type);
	    break;
	default:
	    handler.on_event(*this, event.type);
	    break;
	}
    }
}

class SaveEvents : public GLWindow::EventHandler {
private:
    std::vector<GLWindow::Event>& events;
public:
    SaveEvents(std::vector<GLWindow::Event>& events_) : events(events_) {}
    void on_key_down(GLWindow& win, int key) {
	GLWindow::Event e;
	e.type = GLWindow::Event::KEY_DOWN;
	e.which = key;
	events.push_back(e);
    }
    void on_key_up(GLWindow& win, int key) {
	GLWindow::Event e;
	e.type = GLWindow::Event::KEY_UP;
	e.which = key;
	events.push_back(e);
    }

    void on_mouse_move(GLWindow& win, ImageRef where, int state) {
	GLWindow::Event e;
	e.type = GLWindow::Event::MOUSE_MOVE;
	e.state = state;
	e.where = where;
	events.push_back(e);
    }

    void on_mouse_down(GLWindow& win, ImageRef where, int state, int button) {
	GLWindow::Event e;
	e.type = GLWindow::Event::MOUSE_DOWN;
	e.state = state;
	e.which = button;
	e.where = where;
	events.push_back(e);
    }

    void on_mouse_up(GLWindow& win, ImageRef where, int state, int button) {
	GLWindow::Event e;
	e.type = GLWindow::Event::MOUSE_UP;
	e.state = state;
	e.which = button;
	e.where = where;
	events.push_back(e);
    }

    void on_resize(GLWindow& win, ImageRef size) {
	GLWindow::Event e;
	e.type = GLWindow::Event::RESIZE;
	e.size = size;
	events.push_back(e);
    }

    void on_event(GLWindow& win, int event) {
	GLWindow::Event e;
	e.type = GLWindow::Event::EVENT;
	e.which = event;
	events.push_back(e);
    }
};

void CVD::GLWindow::get_events(std::vector<Event>& events)
{
    SaveEvents saver(events);
    handle_events(saver);
}

bool CVD::GLWindow::EventSummary::should_quit() const
{
    return key_down.count(XK_Escape) || events.count(GLWindow::EVENT_CLOSE);
}

class MakeSummary : public GLWindow::EventHandler {
private:
    GLWindow::EventSummary& summary;
public:
    MakeSummary(GLWindow::EventSummary& summary_) : summary(summary_) {}

    void on_key_down(GLWindow& win, int key) {	++summary.key_down[key]; }
    void on_key_up(GLWindow& win, int key) { ++summary.key_up[key]; }
    void on_mouse_move(GLWindow& win, ImageRef where, int state) { summary.cursor = where; }
    void on_mouse_down(GLWindow& win, ImageRef where, int state, int button) { summary.mouse_down[button] = std::make_pair(where,state); }
    void on_mouse_up(GLWindow& win, ImageRef where, int state, int button) { summary.mouse_up[button] = std::make_pair(where,state); }
    void on_event(GLWindow& win, int event) { ++summary.events[event]; }
};

void GLWindow::get_events(EventSummary& summary)
{
    MakeSummary ms(summary);
    handle_events(ms);
}

bool CVD::GLWindow::has_events() const
{
    return XPending(state->display);
}

void CVD::GLWindow::activate()
{
    if (glXMakeCurrent(state->display, state->window, state->context) == False)
	throw Exceptions::GLWindow::RuntimeError("glXMakeCurrent failed");
}

<|endoftext|>


<commit_before>
/*
   Copyright (c) 2015 Neil Babson and Gabe Stauth
   This source file is protected under the MIT License.
   Please see the file LICENSE in the distribution for license terms.
*/

/*
   This file contains the implementation of the Monte Carlo Search Tree
   which controls the computer AI.
*/

#include "board.h"

//Recursive function that builds the Monte Carlo tree
void gameBoard::MCcheckMoves(MCnode* n, int depth)
{
   move_t temp, bestMoves[4];
   int score, tempi, tempj;
   if (depth > 3)
      return;            // Perform tree search to depth of 3
   // Try passing
   bestMoves[3].wins = MCtryMove(0, 0, n -> color);

   for (int i = 1; i < 10; ++i)
   {
      for (int j = 1; j < 10; ++j)
      {
	 score = MCtryMove(i, j, n -> color);
	 n -> move.wins += PLAYOUTS - score;
	 for (int k = 0; k < 4; ++k)
	 {
	    if (score > bestMoves[k].wins)  // Bubble good moves through array //This doesn't work
	    { // if score is better than all the other scores it replaces all of them
	       if (k == 0)
	       {
		  bestMoves[0].wins = score;
		  bestMoves[0].x = i;
		  bestMoves[0].y = j;
		  //break;
	       }
	       else
	       {
		  temp.wins = bestMoves[k].wins;
		  temp.x = bestMoves[k].x;
		  temp.y = bestMoves[k].y;
		  bestMoves[k].wins = bestMoves[k-1].wins;;
		  bestMoves[k].x = bestMoves[k-1].x;
		  bestMoves[k].y = bestMoves[k-1].y;;
		  bestMoves[k-1].wins = temp.wins;
		  bestMoves[k-1].x = temp.x;
		  bestMoves[k-1].y = temp.y;
		  //break;
	       }
	    }
	 }
/*
         cout << "BestMoves\n";
	 for (int i = 0; i < 4; ++i)
	    cout <<bestMoves[i].wins<< "   ";
	 cout << endl;
*/

      }
   }

   // Put four best moves on the tree
   for (int i = 0; i < 4; ++i)
   {
      n -> next[i] = new MCnode;
      n -> next[i] -> move.wins = bestMoves[i].wins;
      n -> next[i] -> move.x = bestMoves[i].x;
      n -> next[i] -> move.y = bestMoves[i].y;
      n -> next[i] -> board -> copy(n -> board);
      n -> next[i] -> board -> move(bestMoves[i].x, bestMoves[i].y, n -> color);
      n -> next[i] -> parent = n;
      n -> next[i] -> games = PLAYOUTS;
      n -> next[i] -> color = -(n -> color);
      n -> games += PLAYOUTS;
      // Keep total of black wins
//      if (n -> color == 1)
  //       n -> move.wins += bestMoves[i].wins;
  //    else
	 n -> move.wins += PLAYOUTS - bestMoves[i].wins;
      if (DEBUG)
      {
         cout << "Parent's move: " << n->move.x << n->move.y << "      Parents color: " << n->color << "      Parent's wins: " << n->move.wins << endl ;
         cout << "Depth: " << depth << "        Color: " << n->next[i]->color << "      " <<n->next[i]->move.x<<n->next[i]->move.y<< "   My wins: " << n->next[i]->move.wins<<endl;
      }
   }

   // Recursively search children
   ++depth;
   for (int i = 0; i < 4; ++i)
      MCcheckMoves(n -> next[i], depth);

   // Update parent
   if (n -> parent)
   {
      n -> parent -> games += n -> games;
      n -> parent -> move.wins += n-> games - n -> move.wins;
   }
}

//Find and play the most successful move from the second row of the tree
int gameBoard::MCmove()
{
   int bestMove, maxWins = -50000;
   MCnode *root = new MCnode(this);
   root -> color = 1;

   undoOn = false;
   MCcheckMoves(root, 1);
   for (int i = 0; i < 4; ++i)
   {
      if (root -> next[i] -> move.wins > maxWins)
      {
	 maxWins = root -> next[i] -> move.wins;
         bestMove = i;
      }
      if (DEBUG)
         cout << "Children: " << root -> next[i] -> move.wins << "    " << root->next[i]->move.x<<root->next[i]->move.y<<endl;
   }

   undoOn = true;
   if (root -> next[bestMove] -> move.x)  // Best move isn't passing
   {
      this -> move(root->next[bestMove]->move.x, root->next[bestMove]->move.y, 1);   // color = 1
      cout << (char) (root->next[bestMove]->move.x + 96) << root->next[bestMove]->move.y << endl;
      deleteTree(root);
      return 1;
   }
   else                                // Pass
   {
      deleteTree(root);
      koFlag = false;
   }
   return 0;
}

//Delete the search tree after a move is selected
void deleteTree(MCnode * root)
{
   if (!root)
      return;
   for (int i = 0; i < 4; ++i)
      deleteTree(root -> next[i]);
   if (root -> board)
   {
      delete root -> board;
      root -> board = NULL;
   }
   delete root;
   root = NULL;
}

//Perform PLAYOUTS ranndom games from a given starting move and return
//the total won by the color of the argument 'color'
int gameBoard::MCtryMove(int firstx, int firsty, int color)
{
   int wins = 0;
   gameBoard testBoard;

   testBoard.copy(this);
   if (firstx && !testBoard.move(firstx, firsty, color))  // If the first move is illegal return -1
	 return -1;
   for (int i = 0; i < PLAYOUTS; ++i)
      if (MCrandomGame(testBoard, -color, false))
         ++wins;
   return wins;

}

//Plays a random game between two computer players.  If a player attempts to
//make an illegal move 6 times in a row she passes.  If both players pass
//in succession the game ends.
bool gameBoard::MCrandomGame(gameBoard board, int color, bool display)
{
   int startColor = color;
   int x, y;
   int misses, move = 0;
   bool passFlag = false;
   bool done = false;

   do
   {
      if (display)
      {
         cout << "Move " << move << endl;
         board.draw();
      }
      misses = 0;
      do
      {
	 x = (rand() % 9) + 1;
	 y = (rand() % 9) + 1;
	 if (board.move(x, y, color))
	 {
	    passFlag = false;
	    ++move;
	    break;
	 }
	 else
	    misses += 1;
	 if (misses == 6)
	 {
	    if (passFlag)
	       done = true;
	    else
	       passFlag = true;
	    break;
	 }
         ++move;
      }
      while (misses < 6);
      color *= -1;
   }
   while (!done);
   bool  result = board.score(display);
   // If the first move in the random playout was black then the white player's move is
   // being evaluated and we return the opposite of the result from score, which
   // returns true if black won.
   if (startColor == 1)
      return !result;
   else
      return result;
}

//This function orchestrates a game between a human and the Monte Carlo tree algorithm
void MCgame()
{
   gameBoard board;
   char move[3];
   int color = 1;
   bool passFlag = false;
   int choice;

   move[0] = '0';
   do
   {
      board.draw();
      if (color == 1)
      {
	 if (!board.MCmove())
	 {
	    if (passFlag)
	       move[0] = 'q';
	    cout << "Computer pass\n";
	    passFlag = true;
	 }
      }
      else
      {
	 cout << "Enter a move (i.e. g3, p=pass, u=undo, q=quit) : ";
	 cin.get(move, 10, '\n');
	 if (cin.fail())
	    cin.clear();
	 cin.ignore(10, '\n');
	 if (move[0] == 'u')
	    board.undoAgainstAI(color);
	 else if (move[0] == 'p')
	 {
	    if (passFlag)
	       move[0] = 'q';
	    passFlag = true;
	 }
	 else if (move[0] != 'q')
	 {
	    if (!board.move((int)move[0] - 96,(int)move[1] - 48, color))
	    {
	       cout << "Invalid move\n";
	       color *= -1;
	    }
	    else
	       passFlag = false;
	 }
      }
      color *= -1;
   }
   while (move[0] != 'q');
   cout << "Game over\n";
   board.removeDead();
   board.score(true);
}

<commit_msg>Update monte.cpp<commit_after>
/*
   Copyright (c) 2015 Neil Babson and Gabe Stauth
   This source file is protected under the MIT License.
   Please see the file LICENSE in the distribution for license terms.
*/

/*
   This file contains the implementation of the Monte Carlo Search Tree
   which controls the computer AI.
*/

#include "board.h"

//Recursive function that builds the Monte Carlo tree
void gameBoard::MCcheckMoves(MCnode* n, int depth)
{
   move_t temp, bestMoves[4];
   int score, tempi, tempj;
   if (depth > 3)
      return;            // Perform tree search to depth of 3
   // Try passing
   bestMoves[3].wins = MCtryMove(0, 0, n -> color);

   for (int i = 1; i < 10; ++i)
   {
      for (int j = 1; j < 10; ++j)
      {
	 score = MCtryMove(i, j, n -> color);
	 n -> move.wins += PLAYOUTS - score;
	 n -> games += PLAYOUTS;
	 for (int k = 0; k < 4; ++k)
	 {
	    if (score > bestMoves[k].wins)  // Bubble good moves through array
	    { /
	       if (k == 0)
	       {
		  bestMoves[0].wins = score;
		  bestMoves[0].x = i;
		  bestMoves[0].y = j;

	       }
	       else
	       {
		  temp.wins = bestMoves[k].wins;
		  temp.x = bestMoves[k].x;
		  temp.y = bestMoves[k].y;
		  bestMoves[k].wins = bestMoves[k-1].wins;;
		  bestMoves[k].x = bestMoves[k-1].x;
		  bestMoves[k].y = bestMoves[k-1].y;;
		  bestMoves[k-1].wins = temp.wins;
		  bestMoves[k-1].x = temp.x;
		  bestMoves[k-1].y = temp.y;

	       }
	    }
	 }
/*
         cout << "BestMoves\n";
	 for (int i = 0; i < 4; ++i)
	    cout <<bestMoves[i].wins<< "   ";
	 cout << endl;
*/

      }
   }

   // Put four best moves on the tree
   for (int i = 0; i < 4; ++i)
   {
      n -> next[i] = new MCnode;
      n -> next[i] -> move.wins = bestMoves[i].wins;
      n -> next[i] -> move.x = bestMoves[i].x;
      n -> next[i] -> move.y = bestMoves[i].y;
      n -> next[i] -> board -> copy(n -> board);
      n -> next[i] -> board -> move(bestMoves[i].x, bestMoves[i].y, n -> color);
      n -> next[i] -> parent = n;
      n -> next[i] -> games = PLAYOUTS;
      n -> next[i] -> color = -(n -> color);

      n -> games += PLAYOUTS;
      n -> move.wins += PLAYOUTS - bestMoves[i].wins; //double counts the 4 best, so they effectively have double weight
      // Keep total of black wins
//      if (n -> color == 1)
  //       n -> move.wins += bestMoves[i].wins;
  //    else

      if (DEBUG)
      {
         cout << "Parent's move: " << n->move.x << n->move.y << "      Parents color: " << n->color << "      Parent's wins: " << n->move.wins << endl ;
         cout << "Depth: " << depth << "        Color: " << n->next[i]->color << "      " <<n->next[i]->move.x<<n->next[i]->move.y<< "   My wins: " << n->next[i]->move.wins<<endl;
      }
   }

   // Recursively search children
   ++depth;
   for (int i = 0; i < 4; ++i)
      MCcheckMoves(n -> next[i], depth);

   // Update parent
   if (n -> parent)
   {
      n -> parent -> games += n -> games;
      n -> parent -> move.wins += n-> games - n -> move.wins;
   }
}

//Find and play the most successful move from the second row of the tree
int gameBoard::MCmove()
{
   int bestMove, maxWins = -500000;
   MCnode *root = new MCnode(this);
   root -> color = 1;

   undoOn = false;
   MCcheckMoves(root, 1);
   for (int i = 0; i < 4; ++i)
   {
      if (root -> next[i] -> move.wins > maxWins)
      {
	 maxWins = root -> next[i] -> move.wins;
         bestMove = i;
      }
      if (DEBUG)
         cout << "Children: " << root -> next[i] -> move.wins << "    " << root->next[i]->move.x<<root->next[i]->move.y<<endl;
   }

   undoOn = true;
   if (root -> next[bestMove] -> move.x)  // Best move isn't passing
   {
      this -> move(root->next[bestMove]->move.x, root->next[bestMove]->move.y, 1);   // color = 1
      cout << (char) (root->next[bestMove]->move.x + 96) << root->next[bestMove]->move.y << endl;
      deleteTree(root);
      return 1;
   }
   else                                // Pass
   {
      deleteTree(root);
      koFlag = false;
   }
   return 0;
}

//Delete the search tree after a move is selected
void deleteTree(MCnode * root)
{
   if (!root)
      return;
   for (int i = 0; i < 4; ++i)
      deleteTree(root -> next[i]);
   if (root -> board)
   {
      delete root -> board;
      root -> board = NULL;
   }
   delete root;
   root = NULL;
}

//Perform PLAYOUTS ranndom games from a given starting move and return
//the total won by the color of the argument 'color'
int gameBoard::MCtryMove(int firstx, int firsty, int color)
{
   int wins = 0;
   gameBoard testBoard;

   testBoard.copy(this);
   if (firstx && !testBoard.move(firstx, firsty, color))  // If the first move is illegal return -1
	 return -1;
   for (int i = 0; i < PLAYOUTS; ++i)
      if (MCrandomGame(testBoard, -color, false))
         ++wins;
   return wins;

}

//Plays a random game between two computer players.  If a player attempts to
//make an illegal move 6 times in a row she passes.  If both players pass
//in succession the game ends.
bool gameBoard::MCrandomGame(gameBoard board, int color, bool display)
{
   int startColor = color;
   int x, y;
   int misses, move = 0;
   bool passFlag = false;
   bool done = false;

   do
   {
      if (display)
      {
         cout << "Move " << move << endl;
         board.draw();
      }
      misses = 0;
      do
      {
	 x = (rand() % 9) + 1;
	 y = (rand() % 9) + 1;
	 if (board.move(x, y, color))
	 {
	    passFlag = false;
	    ++move;
	    break;
	 }
	 else
	    misses += 1;
	 if (misses == 6)
	 {
	    if (passFlag)
	       done = true;
	    else
	       passFlag = true;
	    break;
	 }
         ++move;
      }
      while (misses < 6);
      color *= -1;
   }
   while (!done);
   bool  result = board.score(display);
   // If the first move in the random playout was black then the white player's move is
   // being evaluated and we return the opposite of the result from score, which
   // returns true if black won.
   if (startColor == 1)
      return !result;
   else
      return result;
}

//This function orchestrates a game between a human and the Monte Carlo tree algorithm
void MCgame()
{
   gameBoard board;
   char move[3];
   int color = 1;
   bool passFlag = false;
   int choice;

   move[0] = '0';
   do
   {
      board.draw();
      if (color == 1)
      {
	 if (!board.MCmove())
	 {
	    if (passFlag)
	       move[0] = 'q';
	    cout << "Computer pass\n";
	    passFlag = true;
	 }
      }
      else
      {
	 cout << "Enter a move (i.e. g3, p=pass, u=undo, q=quit) : ";
	 cin.get(move, 10, '\n');
	 if (cin.fail())
	    cin.clear();
	 cin.ignore(10, '\n');
	 if (move[0] == 'u')
	    board.undoAgainstAI(color);
	 else if (move[0] == 'p')
	 {
	    if (passFlag)
	       move[0] = 'q';
	    passFlag = true;
	 }
	 else if (move[0] != 'q')
	 {
	    if (!board.move((int)move[0] - 96,(int)move[1] - 48, color))
	    {
	       cout << "Invalid move\n";
	       color *= -1;
	    }
	    else
	       passFlag = false;
	 }
      }
      color *= -1;
   }
   while (move[0] != 'q');
   cout << "Game over\n";
   board.removeDead();
   board.score(true);
}

<|endoftext|>


<commit_before>#include <cmath>

#include <vector>
#include <algorithm>
#include <thread>

#include "Python.h"
#include "numpy/arrayobject.h"

#include "kdtree.h"
#include "geometry.h"

typedef geometry::Point<double, 3> Point;

static char module_docstring[] = "Discrete natural neighbor interpolation in 3D.";

static char griddata_docstring[] = "Calculate the natural neighbor interpolation of a dataset.";

static PyObject* cnaturalneighbor_griddata(PyObject* self, PyObject* args);

static PyMethodDef module_methods[] = {
    {"griddata", cnaturalneighbor_griddata, METH_VARARGS, griddata_docstring},
    {NULL, NULL, 0, NULL}
};

static struct PyModuleDef module = {
   PyModuleDef_HEAD_INIT,
   "cnaturalneighbor",
   module_docstring,
   -1,
   module_methods
};

PyMODINIT_FUNC PyInit_cnaturalneighbor(void) {
    PyObject* m = PyModule_Create(&module);
    if (m == NULL) {
        return NULL;
    }

    import_array();  // Enable numpy functionality
    return m;
}

inline long clamp(long val, long min, long max) {
    return std::min(max, std::max(min, val));
}

void inner_loop(
        int thread_number,
        std::size_t ni,
        std::size_t nj,
        std::size_t nk,
        kdtree::kdtree<double> *tree,
        double* interp_values_ptr,
        unsigned long *contribution_counter) {

    for (std::size_t i = 0; i < ni; i++) {
        for (std::size_t j = 0; j < nj; j++) {
            for (std::size_t k = 0; k < nk; k++) {
                auto query_point = Point(i, j, k);
                auto nearest_known_point = tree->nearest_iterative(query_point);

                double distance_sq_query_to_known = nearest_known_point.distance;
                int roi_radius = ceil(sqrt(distance_sq_query_to_known));

                // TODO: ask the programming gods for forgiveness, and then
                // refactor this; this threading model only makes sense for
                // very specific input shapes
                std::size_t i_roi_min, i_roi_max;
                std::size_t i_middle = floor(ni/2);
                if ((thread_number >> 0) % 2) {
                    i_roi_min = clamp(i - roi_radius, 0, i_middle);
                    i_roi_max = clamp(i + roi_radius, 0, i_middle);
                } else {
                    i_roi_min = clamp(i - roi_radius, i_middle + 1, ni - 1);
                    i_roi_max = clamp(i + roi_radius, i_middle + 1, ni - 1);
                }

                std::size_t j_roi_min, j_roi_max;
                std::size_t j_middle = floor(nj/2);
                if ((thread_number >> 1) % 2) {
                    j_roi_min = clamp(j - roi_radius, 0, j_middle);
                    j_roi_max = clamp(j + roi_radius, 0, j_middle);
                } else {
                    j_roi_min = clamp(j - roi_radius, j_middle + 1, nj - 1);
                    j_roi_max = clamp(j + roi_radius, j_middle + 1, nj - 1);
                }

                std::size_t k_roi_min, k_roi_max;
                std::size_t k_middle = floor(nk/2);
                if ((thread_number >> 2) % 2) {
                    k_roi_min = clamp(k - roi_radius, 0, k_middle);
                    k_roi_max = clamp(k + roi_radius, 0, k_middle);
                } else {
                    k_roi_min = clamp(k - roi_radius, k_middle + 1, nk - 1);
                    k_roi_max = clamp(k + roi_radius, k_middle + 1, nk - 1);
                }

                for (std::size_t i_roi = i_roi_min; i_roi <= i_roi_max; i_roi++) {
                    double deltai_2 = (i - i_roi)*(i - i_roi);
                    std::size_t indice_i_component = nj*nk*i_roi;
                    for (std::size_t j_roi = j_roi_min; j_roi <= j_roi_max; j_roi++) {
                        double deltaj_2 = (j - j_roi)*(j - j_roi);
                        std::size_t indice_j_component = nk*j_roi;
                        for (std::size_t k_roi = k_roi_min; k_roi <= k_roi_max; k_roi++) {
                            double deltak_2 = (k - k_roi)*(k - k_roi);
                            double distance_sq_roi_to_known = deltai_2 + deltaj_2 + deltak_2;

                            if (distance_sq_roi_to_known == 0 || distance_sq_roi_to_known < distance_sq_query_to_known) {
                                std::size_t indice = indice_i_component + indice_j_component + k_roi;
                                interp_values_ptr[indice] += nearest_known_point.value;
                                contribution_counter[indice] += 1;
                            }
                        }
                    }
                }
            }
        }
    }
}

static PyObject* cnaturalneighbor_griddata(PyObject* self, PyObject* args) {
    PyArrayObject *known_points_ijk, *known_values, *interp_values;

    if (!PyArg_ParseTuple(args, "O!O!O!",
                &PyArray_Type, &known_points_ijk,
                &PyArray_Type, &known_values,
                &PyArray_Type, &interp_values)) {
        return NULL;
    }

    npy_intp* known_points_ijk_dims = PyArray_DIMS(known_points_ijk);
    std::size_t num_known_points = known_points_ijk_dims[0];

    npy_intp* interp_values_shape = PyArray_DIMS(interp_values);
    std::size_t ni = interp_values_shape[0];
    std::size_t nj = interp_values_shape[1];
    std::size_t nk = interp_values_shape[2];

    double* interp_values_ptr = (double*)PyArray_GETPTR1(interp_values, 0);

    kdtree::kdtree<double> *tree = new kdtree::kdtree<double>();
    for (std::size_t i = 0; i < num_known_points; i++) {
        Point p {
            *(double*)PyArray_GETPTR2(known_points_ijk, i, 0),
            *(double*)PyArray_GETPTR2(known_points_ijk, i, 1),
            *(double*)PyArray_GETPTR2(known_points_ijk, i, 2)
        };
        double v {*(double*)PyArray_GETPTR1(known_values, i)};
        tree->add(p, v);
    }
    tree->build();

    auto contribution_counter = new unsigned long[ni*nj*nk]();

    std::vector<std::thread> threads;
    std::size_t num_threads = 8;  // you can't change this at the moment!
    for (std::size_t thread_number = 0; thread_number < num_threads; thread_number++) {
        threads.push_back(std::thread(&inner_loop,
                thread_number,
                ni,
                nj,
                nk,
                tree,
                interp_values_ptr,
                contribution_counter));
    }

    for (auto& th : threads) {
        th.join();
    }

    for (std::size_t i = 0; i < ni; i++) {
        for (std::size_t j = 0; j < nj; j++) {
            for (std::size_t k = 0; k < nk; k++) {
                auto indice = nj*nk*i + nk*j + k;
                if (contribution_counter[indice] != 0) {
                    interp_values_ptr[indice] /= contribution_counter[indice];
                }
            }
        }
    }

    delete[] contribution_counter;
    delete tree;

    Py_RETURN_NONE;
}
<commit_msg>Make compatibile with Python 2<commit_after>#include <cmath>

#include <vector>
#include <algorithm>
#include <thread>

#include "Python.h"
#include "numpy/arrayobject.h"

#include "kdtree.h"
#include "geometry.h"

typedef geometry::Point<double, 3> Point;

static char module_docstring[] = "Discrete natural neighbor interpolation in 3D.";

static char griddata_docstring[] = "Calculate the natural neighbor interpolation of a dataset.";

static PyObject* cnaturalneighbor_griddata(PyObject* self, PyObject* args);

static PyMethodDef module_methods[] = {
    {"griddata", cnaturalneighbor_griddata, METH_VARARGS, griddata_docstring},
    {NULL, NULL, 0, NULL}
};

/*
The macros below are for backward compatibility with Python 2.
Here, the functions used to creating and initializing modules
differ in both their names and their signatures.

Module initialization
    2: init<name>, void function (does not return a value)
    3: PyInit_<name>, returns either PyObject/NULL for success/failure
Module creation
    2: Py_InitModule3, takes three input arguments
    3: PyModule_Create, takes input args in a single struct

For more, see http://python3porting.com/cextensions.html
*/
#if PY_MAJOR_VERSION >= 3
    #define MOD_ERROR_VAL NULL
    #define MOD_SUCCESS_VAL(val) val
    #define MOD_INIT(name) PyMODINIT_FUNC PyInit_##name(void)
    #define MOD_DEF(ob, name, doc, methods) \
        static struct PyModuleDef module = { \
            PyModuleDef_HEAD_INIT, name, doc, -1, methods, }; \
        ob = PyModule_Create(&module);
#else
    #define MOD_ERROR_VAL
    #define MOD_SUCCESS_VAL(val)
    #define MOD_INIT(name) PyMODINIT_FUNC init##name(void)
    #define MOD_DEF(ob, name, doc, methods) \
        ob = Py_InitModule3(name, methods, doc);
#endif

MOD_INIT(cnaturalneighbor)
{
    PyObject* m;

    MOD_DEF(m, "cnaturalneighbor", module_docstring,
            module_methods)

    if (m == NULL)
        return MOD_ERROR_VAL;

    import_array();

    return MOD_SUCCESS_VAL(m);
}

inline long clamp(long val, long min, long max) {
    return std::min(max, std::max(min, val));
}

void inner_loop(
        int thread_number,
        std::size_t ni,
        std::size_t nj,
        std::size_t nk,
        kdtree::kdtree<double> *tree,
        double* interp_values_ptr,
        unsigned long *contribution_counter) {

    for (std::size_t i = 0; i < ni; i++) {
        for (std::size_t j = 0; j < nj; j++) {
            for (std::size_t k = 0; k < nk; k++) {
                auto query_point = Point(i, j, k);
                auto nearest_known_point = tree->nearest_iterative(query_point);

                double distance_sq_query_to_known = nearest_known_point.distance;
                int roi_radius = ceil(sqrt(distance_sq_query_to_known));

                // TODO: ask the programming gods for forgiveness, and then
                // refactor this; this threading model only makes sense for
                // very specific input shapes
                std::size_t i_roi_min, i_roi_max;
                std::size_t i_middle = floor(ni/2);
                if ((thread_number >> 0) % 2) {
                    i_roi_min = clamp(i - roi_radius, 0, i_middle);
                    i_roi_max = clamp(i + roi_radius, 0, i_middle);
                } else {
                    i_roi_min = clamp(i - roi_radius, i_middle + 1, ni - 1);
                    i_roi_max = clamp(i + roi_radius, i_middle + 1, ni - 1);
                }

                std::size_t j_roi_min, j_roi_max;
                std::size_t j_middle = floor(nj/2);
                if ((thread_number >> 1) % 2) {
                    j_roi_min = clamp(j - roi_radius, 0, j_middle);
                    j_roi_max = clamp(j + roi_radius, 0, j_middle);
                } else {
                    j_roi_min = clamp(j - roi_radius, j_middle + 1, nj - 1);
                    j_roi_max = clamp(j + roi_radius, j_middle + 1, nj - 1);
                }

                std::size_t k_roi_min, k_roi_max;
                std::size_t k_middle = floor(nk/2);
                if ((thread_number >> 2) % 2) {
                    k_roi_min = clamp(k - roi_radius, 0, k_middle);
                    k_roi_max = clamp(k + roi_radius, 0, k_middle);
                } else {
                    k_roi_min = clamp(k - roi_radius, k_middle + 1, nk - 1);
                    k_roi_max = clamp(k + roi_radius, k_middle + 1, nk - 1);
                }

                for (std::size_t i_roi = i_roi_min; i_roi <= i_roi_max; i_roi++) {
                    double deltai_2 = (i - i_roi)*(i - i_roi);
                    std::size_t indice_i_component = nj*nk*i_roi;
                    for (std::size_t j_roi = j_roi_min; j_roi <= j_roi_max; j_roi++) {
                        double deltaj_2 = (j - j_roi)*(j - j_roi);
                        std::size_t indice_j_component = nk*j_roi;
                        for (std::size_t k_roi = k_roi_min; k_roi <= k_roi_max; k_roi++) {
                            double deltak_2 = (k - k_roi)*(k - k_roi);
                            double distance_sq_roi_to_known = deltai_2 + deltaj_2 + deltak_2;

                            if (distance_sq_roi_to_known == 0 || distance_sq_roi_to_known < distance_sq_query_to_known) {
                                std::size_t indice = indice_i_component + indice_j_component + k_roi;
                                interp_values_ptr[indice] += nearest_known_point.value;
                                contribution_counter[indice] += 1;
                            }
                        }
                    }
                }
            }
        }
    }
}

static PyObject* cnaturalneighbor_griddata(PyObject* self, PyObject* args) {
    PyArrayObject *known_points_ijk, *known_values, *interp_values;

    if (!PyArg_ParseTuple(args, "O!O!O!",
                &PyArray_Type, &known_points_ijk,
                &PyArray_Type, &known_values,
                &PyArray_Type, &interp_values)) {
        return NULL;
    }

    npy_intp* known_points_ijk_dims = PyArray_DIMS(known_points_ijk);
    std::size_t num_known_points = known_points_ijk_dims[0];

    npy_intp* interp_values_shape = PyArray_DIMS(interp_values);
    std::size_t ni = interp_values_shape[0];
    std::size_t nj = interp_values_shape[1];
    std::size_t nk = interp_values_shape[2];

    double* interp_values_ptr = (double*)PyArray_GETPTR1(interp_values, 0);

    kdtree::kdtree<double> *tree = new kdtree::kdtree<double>();
    for (std::size_t i = 0; i < num_known_points; i++) {
        Point p {
            *(double*)PyArray_GETPTR2(known_points_ijk, i, 0),
            *(double*)PyArray_GETPTR2(known_points_ijk, i, 1),
            *(double*)PyArray_GETPTR2(known_points_ijk, i, 2)
        };
        double v {*(double*)PyArray_GETPTR1(known_values, i)};
        tree->add(p, v);
    }
    tree->build();

    auto contribution_counter = new unsigned long[ni*nj*nk]();

    std::vector<std::thread> threads;
    std::size_t num_threads = 8;  // you can't change this at the moment!
    for (std::size_t thread_number = 0; thread_number < num_threads; thread_number++) {
        threads.push_back(std::thread(&inner_loop,
                thread_number,
                ni,
                nj,
                nk,
                tree,
                interp_values_ptr,
                contribution_counter));
    }

    for (auto& th : threads) {
        th.join();
    }

    for (std::size_t i = 0; i < ni; i++) {
        for (std::size_t j = 0; j < nj; j++) {
            for (std::size_t k = 0; k < nk; k++) {
                auto indice = nj*nk*i + nk*j + k;
                if (contribution_counter[indice] != 0) {
                    interp_values_ptr[indice] /= contribution_counter[indice];
                }
            }
        }
    }

    delete[] contribution_counter;
    delete tree;

    Py_RETURN_NONE;
}
<|endoftext|>