<commit_before>/*
-----------------------------------------------------------------------------
This source file is part of OGRE
	(Object-oriented Graphics Rendering Engine)
For the latest info, see http://www.ogre3d.org/

Copyright (c) 2000-2013 Torus Knot Software Ltd

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

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

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

#include "OgreGLRenderSystem.h"
#include "OgreRoot.h"
#include "OgreGLXContext.h"
#include "OgreGLXUtils.h"
#include "OgreGLXGLSupport.h"

namespace Ogre
{
	GLXContext::GLXContext(GLXGLSupport* glsupport, ::GLXFBConfig fbconfig, ::GLXDrawable drawable, ::GLXContext context) :
		mDrawable(drawable), mContext(0), mFBConfig(fbconfig), mGLSupport(glsupport), mExternalContext(false)
	{
		GLRenderSystem *renderSystem = static_cast<GLRenderSystem*>(Root::getSingleton().getRenderSystem());
		GLXContext* mainContext = static_cast<GLXContext*>(renderSystem->_getMainContext());
		::GLXContext shareContext = 0;

		if (mainContext)
		{
			shareContext = mainContext->mContext;
		}

		if (context)
		{
			mContext = context;
			mExternalContext = true;
		}
		else
		{
			mContext = mGLSupport->createNewContext(mFBConfig, GLX_RGBA_TYPE, shareContext, GL_TRUE);
		}

		if (! mContext)
		{
			OGRE_EXCEPT(Exception::ERR_RENDERINGAPI_ERROR, "Unable to create a suitable GLXContext", "GLXContext::GLXContext");
		}
	}

	GLXContext::~GLXContext()
	{
		GLRenderSystem *rs = static_cast<GLRenderSystem*>(Root::getSingleton().getRenderSystem());

                printf("BELIEVE IN LOVE\n");

		if (!mExternalContext)
                    glXDestroyContext(mGLSupport->getGLDisplay(), mContext);

                printf("AFTER LOVE\n");

		rs->_unregisterContext(this);
	}

	void GLXContext::setCurrent()
	{
		glXMakeCurrent(mGLSupport->getGLDisplay(), mDrawable, mContext);
	}

	void GLXContext::endCurrent()
	{
		glXMakeCurrent(mGLSupport->getGLDisplay(), None, None);
	}

	GLContext* GLXContext::clone() const
	{
		return new GLXContext(mGLSupport, mFBConfig, mDrawable);
	}
}
<commit_msg>[GL] Remove debug statements<commit_after>/*
-----------------------------------------------------------------------------
This source file is part of OGRE
	(Object-oriented Graphics Rendering Engine)
For the latest info, see http://www.ogre3d.org/

Copyright (c) 2000-2013 Torus Knot Software Ltd

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

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

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

#include "OgreGLRenderSystem.h"
#include "OgreRoot.h"
#include "OgreGLXContext.h"
#include "OgreGLXUtils.h"
#include "OgreGLXGLSupport.h"

namespace Ogre
{
	GLXContext::GLXContext(GLXGLSupport* glsupport, ::GLXFBConfig fbconfig, ::GLXDrawable drawable, ::GLXContext context) :
		mDrawable(drawable), mContext(0), mFBConfig(fbconfig), mGLSupport(glsupport), mExternalContext(false)
	{
		GLRenderSystem *renderSystem = static_cast<GLRenderSystem*>(Root::getSingleton().getRenderSystem());
		GLXContext* mainContext = static_cast<GLXContext*>(renderSystem->_getMainContext());
		::GLXContext shareContext = 0;

		if (mainContext)
		{
			shareContext = mainContext->mContext;
		}

		if (context)
		{
			mContext = context;
			mExternalContext = true;
		}
		else
		{
			mContext = mGLSupport->createNewContext(mFBConfig, GLX_RGBA_TYPE, shareContext, GL_TRUE);
		}

		if (! mContext)
		{
			OGRE_EXCEPT(Exception::ERR_RENDERINGAPI_ERROR, "Unable to create a suitable GLXContext", "GLXContext::GLXContext");
		}
	}

	GLXContext::~GLXContext()
	{
		GLRenderSystem *rs = static_cast<GLRenderSystem*>(Root::getSingleton().getRenderSystem());

		if (!mExternalContext)
                    glXDestroyContext(mGLSupport->getGLDisplay(), mContext);

		rs->_unregisterContext(this);
	}

	void GLXContext::setCurrent()
	{
		glXMakeCurrent(mGLSupport->getGLDisplay(), mDrawable, mContext);
	}

	void GLXContext::endCurrent()
	{
		glXMakeCurrent(mGLSupport->getGLDisplay(), None, None);
	}

	GLContext* GLXContext::clone() const
	{
		return new GLXContext(mGLSupport, mFBConfig, mDrawable);
	}
}
<|endoftext|>


<commit_before>#include "Mesh.h"
#include "DefaultRenderTypes.h"
#include "DefaultShaderLoader.h"
#include "MeshManager.hpp"
#include "Utility.hpp"

using namespace Device;
using namespace Rendering;
using namespace Rendering::Geometry;
using namespace Rendering::Shader;
using namespace Rendering::Manager;
using namespace Rendering::Buffer;
using namespace Core;
using namespace Utility;
using namespace Math;
using namespace Intersection;

void Mesh::Initialize(Device::DirectX& dx, BufferManager& bufferMgr, const CreateFuncArguments& args)
{
	uint vertexCount	= args.vertices.count;
	uint indexCount		= args.indices.size();

	String::MakeKey({ args.fileName, args.ibPartID });
	uint vbKey = Utility::String::MakeKey({ args.fileName, std::to_string(args.vbUserHashKey) });

	if (bufferMgr.GetPool<VertexBuffer>().Has(vbKey) == false)
	{
		VertexBuffer::Desc param;
		{
			param.stride		= args.vertices.byteWidth;
			param.vertexCount	= args.vertices.count;
		}

		VertexBuffer vb;
		vb.Initialize(dx, param, args.vertices.data, args.useDynamicVB, args.semanticInfos);

		bufferMgr.GetPool<VertexBuffer>().Add(vbKey, vb);
		_vbKey = vbKey;
	}

	uint ibKey = String::MakeKey({ args.fileName, args.ibPartID });
	if (bufferMgr.GetPool<IndexBuffer>().Has(ibKey) == false)
	{
		IndexBuffer ib;
		ib.Initialize(dx, args.indices, vbKey, args.useDynamicIB);

		bufferMgr.GetPool<IndexBuffer>().Add(ibKey, ib);
		_ibKey = ibKey;
	}

	_bufferFlag = ComputeBufferFlag(args.semanticInfos);

	_transformCB.Initialize(dx);
}

void Mesh::Initialize(const VertexBuffer::Semantics& semantics, BaseBuffer::Key vbKey, BaseBuffer::Key ibKey)
{
	_vbKey = vbKey;
	_ibKey = ibKey;

	_bufferFlag = ComputeBufferFlag(semantics);
}

uint Mesh::ComputeBufferFlag(const std::vector<VertexShader::SemanticInfo>& semantics, uint maxRecognizeBoneCount) const
{
	uint flag = 0;
	for (auto iter = semantics.begin(); iter != semantics.end(); ++iter)
	{
		const auto& semantic = *iter;

		if (semantic.name == "POSITION")		continue;
		else if (semantic.name == "TEXCOORD")
		{
			if (semantic.semanticIndex > 1)
				flag |= static_cast<uint>(DefaultVertexInputTypeFlag::USERS);
			else
				flag |= static_cast<uint>(DefaultVertexInputTypeFlag::UV0) << semantic.semanticIndex;
		}
		else if (semantic.name == "NORMAL")
			flag |= static_cast<uint>(DefaultVertexInputTypeFlag::NORMAL);
		else if (semantic.name == "TANGENT")
			flag |= static_cast<uint>(DefaultVertexInputTypeFlag::TANGENT);
		else if (semantic.name == "COLOR")
			flag |= static_cast<uint>(DefaultVertexInputTypeFlag::COLOR);
		else if (semantic.name == "BONEWEIGHT")
		{
			if (semantic.semanticIndex + 1 >= maxRecognizeBoneCount)
				flag |= static_cast<uint>(DefaultVertexInputTypeFlag::BONE) << semantic.semanticIndex;
			else
				flag |= static_cast<uint>(DefaultVertexInputTypeFlag::USERS);
		}
		else
		{
			flag |= static_cast<uint>(DefaultVertexInputTypeFlag::USERS);
		}
	}

	// Error, You use undefined semantic in RenderManager::DefaultVertexInputTypeFlag.
	assert((flag & static_cast<uint>(DefaultVertexInputTypeFlag::USERS)) == 0);

	return flag;
}

void Mesh::AddMaterialID(MaterialID id)
{
	assert(id.Literal() != MaterialID::Undefined());
	_materialIDs.push_back(id);
}

bool Mesh::HasMaterialID(MaterialID id) const
{
	for (auto& iter : _materialIDs)
	{
		if (iter == id)
			return true;
	}

	return false;
}

void Mesh::DeleteMaterialID(MaterialID id)
{
	uint size = _materialIDs.size();
	for (uint i = 0; i < size; ++i)
	{
		if (_materialIDs[i] == id)
		{
			_materialIDs.erase( _materialIDs.begin() + i );
			return;
		}
	}
}

void Mesh::CalcWorldSize(Math::Vector3& worldMin, Math::Vector3& worldMax, const Core::Transform& transform) const
{
	assert(transform.GetDirty());

	Vector3 extents = _boundBox.GetExtents();
	Vector3 boxCenter = _boundBox.GetCenter();

	const Matrix& worldMat = transform.GetWorldMatrix();
	Vector3 worldPos = Vector3(worldMat._41, worldMat._42, worldMat._43) + boxCenter;

	Vector3 worldScale = transform.GetWorldScale();

	Vector3 minPos = (worldPos - extents) * worldScale;
	Vector3 maxPos = (worldPos + extents) * worldScale;

	if (worldMin.x > minPos.x) worldMin.x = minPos.x;
	if (worldMin.y > minPos.y) worldMin.y = minPos.y;
	if (worldMin.z > minPos.z) worldMin.z = minPos.z;

	if (worldMax.x < maxPos.x) worldMax.x = maxPos.x;
	if (worldMax.y < maxPos.y) worldMax.y = maxPos.y;
	if (worldMax.z < maxPos.z) worldMax.z = maxPos.z;
}

void Mesh::UpdateTransformCB(DirectX& dx, const Transform& transform)
{
	assert(transform.GetObjectID() == _objectID);

	if(transform.GetDirty())
		_tfChangeState = TransformCB::ChangeState::HasChanged;

	if ((_tfChangeState != TransformCB::ChangeState::No) == false)
		return;

	const Matrix& worldMat = transform.GetWorldMatrix();

	TransformCB tfCB;
	tfCB.world				= Matrix::Transpose(worldMat);
	tfCB.prevWorld			= Matrix::Transpose(_prevWorldMat);
	tfCB.worldInvTranspose	= Matrix::Inverse(tfCB.world);
	_transformCB.UpdateSubResource(dx, tfCB);

	_prevWorldMat = worldMat;
	_tfChangeState = TransformCB::ChangeState((static_cast<uint>(_tfChangeState) + 1) % static_cast<uint>(TransformCB::ChangeState::MAX));
}
<commit_msg>Mesh - 불필요한 코드 제거<commit_after>#include "Mesh.h"
#include "DefaultRenderTypes.h"
#include "DefaultShaderLoader.h"
#include "MeshManager.hpp"
#include "Utility.hpp"

using namespace Device;
using namespace Rendering;
using namespace Rendering::Geometry;
using namespace Rendering::Shader;
using namespace Rendering::Manager;
using namespace Rendering::Buffer;
using namespace Core;
using namespace Utility;
using namespace Math;
using namespace Intersection;

void Mesh::Initialize(Device::DirectX& dx, BufferManager& bufferMgr, const CreateFuncArguments& args)
{
	uint vertexCount	= args.vertices.count;
	uint indexCount		= args.indices.size();

	uint vbKey = Utility::String::MakeKey({ args.fileName, std::to_string(args.vbUserHashKey) });

	if (bufferMgr.GetPool<VertexBuffer>().Has(vbKey) == false)
	{
		VertexBuffer::Desc param;
		{
			param.stride		= args.vertices.byteWidth;
			param.vertexCount	= args.vertices.count;
		}

		VertexBuffer vb;
		vb.Initialize(dx, param, args.vertices.data, args.useDynamicVB, args.semanticInfos);

		bufferMgr.GetPool<VertexBuffer>().Add(vbKey, vb);
		_vbKey = vbKey;
	}

	uint ibKey = String::MakeKey({ args.fileName, args.ibPartID });
	if (bufferMgr.GetPool<IndexBuffer>().Has(ibKey) == false)
	{
		IndexBuffer ib;
		ib.Initialize(dx, args.indices, vbKey, args.useDynamicIB);

		bufferMgr.GetPool<IndexBuffer>().Add(ibKey, ib);
		_ibKey = ibKey;
	}

	_bufferFlag = ComputeBufferFlag(args.semanticInfos);

	_transformCB.Initialize(dx);
}

void Mesh::Initialize(const VertexBuffer::Semantics& semantics, BaseBuffer::Key vbKey, BaseBuffer::Key ibKey)
{
	_vbKey = vbKey;
	_ibKey = ibKey;

	_bufferFlag = ComputeBufferFlag(semantics);
}

uint Mesh::ComputeBufferFlag(const std::vector<VertexShader::SemanticInfo>& semantics, uint maxRecognizeBoneCount) const
{
	uint flag = 0;
	for (auto iter = semantics.begin(); iter != semantics.end(); ++iter)
	{
		const auto& semantic = *iter;

		if (semantic.name == "POSITION")		continue;
		else if (semantic.name == "TEXCOORD")
		{
			if (semantic.semanticIndex > 1)
				flag |= static_cast<uint>(DefaultVertexInputTypeFlag::USERS);
			else
				flag |= static_cast<uint>(DefaultVertexInputTypeFlag::UV0) << semantic.semanticIndex;
		}
		else if (semantic.name == "NORMAL")
			flag |= static_cast<uint>(DefaultVertexInputTypeFlag::NORMAL);
		else if (semantic.name == "TANGENT")
			flag |= static_cast<uint>(DefaultVertexInputTypeFlag::TANGENT);
		else if (semantic.name == "COLOR")
			flag |= static_cast<uint>(DefaultVertexInputTypeFlag::COLOR);
		else if (semantic.name == "BONEWEIGHT")
		{
			if (semantic.semanticIndex + 1 >= maxRecognizeBoneCount)
				flag |= static_cast<uint>(DefaultVertexInputTypeFlag::BONE) << semantic.semanticIndex;
			else
				flag |= static_cast<uint>(DefaultVertexInputTypeFlag::USERS);
		}
		else
		{
			flag |= static_cast<uint>(DefaultVertexInputTypeFlag::USERS);
		}
	}

	// Error, You use undefined semantic in RenderManager::DefaultVertexInputTypeFlag.
	assert((flag & static_cast<uint>(DefaultVertexInputTypeFlag::USERS)) == 0);

	return flag;
}

void Mesh::AddMaterialID(MaterialID id)
{
	assert(id.Literal() != MaterialID::Undefined());
	_materialIDs.push_back(id);
}

bool Mesh::HasMaterialID(MaterialID id) const
{
	for (auto& iter : _materialIDs)
	{
		if (iter == id)
			return true;
	}

	return false;
}

void Mesh::DeleteMaterialID(MaterialID id)
{
	uint size = _materialIDs.size();
	for (uint i = 0; i < size; ++i)
	{
		if (_materialIDs[i] == id)
		{
			_materialIDs.erase( _materialIDs.begin() + i );
			return;
		}
	}
}

void Mesh::CalcWorldSize(Math::Vector3& worldMin, Math::Vector3& worldMax, const Core::Transform& transform) const
{
	assert(transform.GetDirty());

	Vector3 extents = _boundBox.GetExtents();
	Vector3 boxCenter = _boundBox.GetCenter();

	const Matrix& worldMat = transform.GetWorldMatrix();
	Vector3 worldPos = Vector3(worldMat._41, worldMat._42, worldMat._43) + boxCenter;

	Vector3 worldScale = transform.GetWorldScale();

	Vector3 minPos = (worldPos - extents) * worldScale;
	Vector3 maxPos = (worldPos + extents) * worldScale;

	if (worldMin.x > minPos.x) worldMin.x = minPos.x;
	if (worldMin.y > minPos.y) worldMin.y = minPos.y;
	if (worldMin.z > minPos.z) worldMin.z = minPos.z;

	if (worldMax.x < maxPos.x) worldMax.x = maxPos.x;
	if (worldMax.y < maxPos.y) worldMax.y = maxPos.y;
	if (worldMax.z < maxPos.z) worldMax.z = maxPos.z;
}

void Mesh::UpdateTransformCB(DirectX& dx, const Transform& transform)
{
	assert(transform.GetObjectID() == _objectID);

	if(transform.GetDirty())
		_tfChangeState = TransformCB::ChangeState::HasChanged;

	if ((_tfChangeState != TransformCB::ChangeState::No) == false)
		return;

	const Matrix& worldMat = transform.GetWorldMatrix();

	TransformCB tfCB;
	tfCB.world				= Matrix::Transpose(worldMat);
	tfCB.prevWorld			= Matrix::Transpose(_prevWorldMat);
	tfCB.worldInvTranspose	= Matrix::Inverse(tfCB.world);
	_transformCB.UpdateSubResource(dx, tfCB);

	_prevWorldMat = worldMat;
	_tfChangeState = TransformCB::ChangeState((static_cast<uint>(_tfChangeState) + 1) % static_cast<uint>(TransformCB::ChangeState::MAX));
}
<|endoftext|>


<commit_before>/*
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 3 of the License, or
 * (at your option) any later version.
 *
 * Written (W) 1999-2009 Soeren Sonnenburg
 * Written (W) 1999-2008 Gunnar Raetsch
 * Copyright (C) 1999-2009 Fraunhofer Institute FIRST and Max-Planck-Society
 */

#include "features/Features.h"
#include "preproc/PreProc.h"
#include "lib/io.h"
#include "base/Parameter.h"

#include <string.h>

using namespace shogun;

CFeatures::CFeatures(int32_t size)
: CSGObject()
{
	init();
	cache_size = size;
}

CFeatures::CFeatures(const CFeatures& orig)
: CSGObject(orig)
{
	init();

	preproc = orig.preproc;
	num_preproc = orig.num_preproc;

	preprocessed=new bool[orig.num_preproc];
	memcpy(preprocessed, orig.preprocessed, sizeof(bool)*orig.num_preproc);
}

CFeatures::CFeatures(CFile* loader)
: CSGObject()
{
	init();

	load(loader);
	SG_INFO("Feature object loaded (%p)\n",this) ;
}

CFeatures::~CFeatures()
{
	if (m_subset_idx)
		delete[] m_subset_idx;

	clean_preprocs();
}

void
CFeatures::init(void)
{
	m_parameters->add(&properties, "properties",
					  "Feature properties.");
	m_parameters->add(&cache_size, "cache_size",
					  "Size of cache in MB.");

	m_parameters->add_vector((CSGObject***) &preproc,
							 &num_preproc, "preproc",
							 "List of preprocessors.");
	m_parameters->add_vector(&preprocessed,
							 &num_preproc, "preprocessed",
							 "Feature[i] is already preprocessed.");

	m_parameters->add_vector(&m_subset_idx, &m_subset_len, "subset_idx", "Subset indices.");

	properties = FP_NONE;
	cache_size = 0;
	preproc = NULL;
	num_preproc = 0;
	preprocessed = NULL;
	m_subset_idx = NULL;
	m_subset_len = 0;
}

/// set preprocessor
int32_t CFeatures::add_preproc(CPreProc* p)
{
	SG_INFO( "%d preprocs currently, new preproc list is\n", num_preproc);
	ASSERT(p);

	bool* preprocd=new bool[num_preproc+1];
	CPreProc** pps=new CPreProc*[num_preproc+1];
	for (int32_t i=0; i<num_preproc; i++)
	{
		pps[i]=preproc[i];
		preprocd[i]=preprocessed[i];
	}
	delete[] preproc;
	delete[] preprocessed;
	preproc=pps;
	preprocessed=preprocd;
	preproc[num_preproc]=p;
	preprocessed[num_preproc]=false;

	num_preproc++;

	for (int32_t i=0; i<num_preproc; i++)
		SG_INFO( "preproc[%d]=%s %ld\n",i, preproc[i]->get_name(), preproc[i]) ;

	SG_REF(p);

	return num_preproc;
}

/// get current preprocessor
CPreProc* CFeatures::get_preproc(int32_t num)
{
	if (num<num_preproc)
	{
		SG_REF(preproc[num]);
		return preproc[num];
	}
	else
		return NULL;
}

/// get whether specified preprocessor (or all if num=1) was/were already applied
int32_t CFeatures::get_num_preprocessed()
{
	int32_t num=0;

	for (int32_t i=0; i<num_preproc; i++)
	{
		if (preprocessed[i])
			num++;
	}

	return num;
}

/// clears all preprocs
void CFeatures::clean_preprocs()
{
	while (del_preproc(0));
}

/// del current preprocessor
CPreProc* CFeatures::del_preproc(int32_t num)
{
	CPreProc** pps=NULL;
	bool* preprocd=NULL;
	CPreProc* removed_preproc=NULL;

	if (num_preproc>0 && num<num_preproc)
	{
		removed_preproc=preproc[num];

		if (num_preproc>1)
		{
			pps= new CPreProc*[num_preproc-1];
			preprocd= new bool[num_preproc-1];

			if (pps && preprocd)
			{
				int32_t j=0;
				for (int32_t i=0; i<num_preproc; i++)
				{
					if (i!=num)
					{
						pps[j]=preproc[i];
						preprocd[j]=preprocessed[i];
						j++;
					}
				}
			}
		}

		delete[] preproc;
		preproc=pps;
		delete[] preprocessed;
		preprocessed=preprocd;

		num_preproc--;

		for (int32_t i=0; i<num_preproc; i++)
			SG_INFO( "preproc[%d]=%s\n",i, preproc[i]->get_name()) ;
	}

	SG_UNREF(removed_preproc);
	return removed_preproc;
}

void CFeatures::list_feature_obj()
{
	SG_INFO( "%p - ", this);
	switch (get_feature_class())
	{
		case C_UNKNOWN:
			SG_INFO( "C_UNKNOWN ");
			break;
		case C_SIMPLE:
			SG_INFO( "C_SIMPLE ");
			break;
		case C_SPARSE:
			SG_INFO( "C_SPARSE ");
			break;
		case C_STRING:
			SG_INFO( "C_STRING ");
			break;
		case C_COMBINED:
			SG_INFO( "C_COMBINED ");
			break;
		case C_COMBINED_DOT:
			SG_INFO( "C_COMBINED_DOT ");
			break;
		case C_WD:
			SG_INFO( "C_WD ");
			break;
		case C_SPEC:
			SG_INFO( "C_SPEC ");
			break;
		case C_WEIGHTEDSPEC:
			SG_INFO( "C_WEIGHTEDSPEC ");
			break;
		case C_ANY:
			SG_INFO( "C_ANY ");
			break;
		default:
         SG_ERROR( "ERROR UNKNOWN FEATURE CLASS");
	}

	switch (get_feature_type())
	{
		case F_UNKNOWN:
			SG_INFO( "F_UNKNOWN \n");
			break;
		case F_CHAR:
			SG_INFO( "F_CHAR \n");
			break;
		case F_BYTE:
			SG_INFO( "F_BYTE \n");
			break;
		case F_SHORT:
			SG_INFO( "F_SHORT \n");
			break;
		case F_WORD:
			SG_INFO( "F_WORD \n");
			break;
		case F_INT:
			SG_INFO( "F_INT \n");
			break;
		case F_UINT:
			SG_INFO( "F_UINT \n");
			break;
		case F_LONG:
			SG_INFO( "F_LONG \n");
			break;
		case F_ULONG:
			SG_INFO( "F_ULONG \n");
			break;
		case F_SHORTREAL:
			SG_INFO( "F_SHORTEAL \n");
			break;
		case F_DREAL:
			SG_INFO( "F_DREAL \n");
			break;
		case F_LONGREAL:
			SG_INFO( "F_LONGREAL \n");
			break;
		case F_ANY:
			SG_INFO( "F_ANY \n");
			break;
		default:
         SG_ERROR( "ERROR UNKNOWN FEATURE TYPE\n");
	}
}

bool CFeatures::check_feature_compatibility(CFeatures* f)
{
	bool result=false;

	if (f)
		result= ( (this->get_feature_class() == f->get_feature_class()) &&
				(this->get_feature_type() == f->get_feature_type()));
	return result;
}

void CFeatures::set_feature_subset(int32_t subset_len, int32_t* subset_idx)
{
	if (m_subset_idx)
		delete[] m_subset_idx;

	m_subset_idx=subset_idx;
	m_subset_len=subset_len;
}

void CFeatures::set_feature_subset(int32_t* subset_idx, int32_t subset_len)
{
	ASSERT(subset_idx);

	delete[] m_subset_idx;
	m_subset_idx = NULL;

	int64_t length=sizeof(int32_t)*subset_len;

	m_subset_idx=(int32_t*) SG_MALLOC(length);
	if (!m_subset_idx)
		SG_ERROR("Allocating %ld bytes failes\n", length);

	memcpy(m_subset_idx, subset_idx, length);
}

void CFeatures::remove_feature_subset()
{
	if (!m_subset_idx)
	{
		delete[] m_subset_idx;
		m_subset_idx=NULL;
		m_subset_len=0;
	}
}

void CFeatures::get_feature_subset(int32_t** subset_idx, int32_t* subset_len)
{
	ASSERT(m_subset_idx);
	int64_t length = sizeof(int32_t)*m_subset_len;

	*subset_len=m_subset_len;
	*subset_idx=(int32_t*) SG_MALLOC(length);
	if (!*subset_idx)
		SG_ERROR("Allocating %ld bytes failes\n", length);
	memcpy(*subset_idx, m_subset_idx, length);
}
<commit_msg>removed malloc success check due to new usage of SG_MALLOC<commit_after>/*
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 3 of the License, or
 * (at your option) any later version.
 *
 * Written (W) 1999-2009 Soeren Sonnenburg
 * Written (W) 1999-2008 Gunnar Raetsch
 * Copyright (C) 1999-2009 Fraunhofer Institute FIRST and Max-Planck-Society
 */

#include "features/Features.h"
#include "preproc/PreProc.h"
#include "lib/io.h"
#include "base/Parameter.h"

#include <string.h>

using namespace shogun;

CFeatures::CFeatures(int32_t size)
: CSGObject()
{
	init();
	cache_size = size;
}

CFeatures::CFeatures(const CFeatures& orig)
: CSGObject(orig)
{
	init();

	preproc = orig.preproc;
	num_preproc = orig.num_preproc;

	preprocessed=new bool[orig.num_preproc];
	memcpy(preprocessed, orig.preprocessed, sizeof(bool)*orig.num_preproc);
}

CFeatures::CFeatures(CFile* loader)
: CSGObject()
{
	init();

	load(loader);
	SG_INFO("Feature object loaded (%p)\n",this) ;
}

CFeatures::~CFeatures()
{
	if (m_subset_idx)
		delete[] m_subset_idx;

	clean_preprocs();
}

void
CFeatures::init(void)
{
	m_parameters->add(&properties, "properties",
					  "Feature properties.");
	m_parameters->add(&cache_size, "cache_size",
					  "Size of cache in MB.");

	m_parameters->add_vector((CSGObject***) &preproc,
							 &num_preproc, "preproc",
							 "List of preprocessors.");
	m_parameters->add_vector(&preprocessed,
							 &num_preproc, "preprocessed",
							 "Feature[i] is already preprocessed.");

	m_parameters->add_vector(&m_subset_idx, &m_subset_len, "subset_idx", "Subset indices.");

	properties = FP_NONE;
	cache_size = 0;
	preproc = NULL;
	num_preproc = 0;
	preprocessed = NULL;
	m_subset_idx = NULL;
	m_subset_len = 0;
}

/// set preprocessor
int32_t CFeatures::add_preproc(CPreProc* p)
{
	SG_INFO( "%d preprocs currently, new preproc list is\n", num_preproc);
	ASSERT(p);

	bool* preprocd=new bool[num_preproc+1];
	CPreProc** pps=new CPreProc*[num_preproc+1];
	for (int32_t i=0; i<num_preproc; i++)
	{
		pps[i]=preproc[i];
		preprocd[i]=preprocessed[i];
	}
	delete[] preproc;
	delete[] preprocessed;
	preproc=pps;
	preprocessed=preprocd;
	preproc[num_preproc]=p;
	preprocessed[num_preproc]=false;

	num_preproc++;

	for (int32_t i=0; i<num_preproc; i++)
		SG_INFO( "preproc[%d]=%s %ld\n",i, preproc[i]->get_name(), preproc[i]) ;

	SG_REF(p);

	return num_preproc;
}

/// get current preprocessor
CPreProc* CFeatures::get_preproc(int32_t num)
{
	if (num<num_preproc)
	{
		SG_REF(preproc[num]);
		return preproc[num];
	}
	else
		return NULL;
}

/// get whether specified preprocessor (or all if num=1) was/were already applied
int32_t CFeatures::get_num_preprocessed()
{
	int32_t num=0;

	for (int32_t i=0; i<num_preproc; i++)
	{
		if (preprocessed[i])
			num++;
	}

	return num;
}

/// clears all preprocs
void CFeatures::clean_preprocs()
{
	while (del_preproc(0));
}

/// del current preprocessor
CPreProc* CFeatures::del_preproc(int32_t num)
{
	CPreProc** pps=NULL;
	bool* preprocd=NULL;
	CPreProc* removed_preproc=NULL;

	if (num_preproc>0 && num<num_preproc)
	{
		removed_preproc=preproc[num];

		if (num_preproc>1)
		{
			pps= new CPreProc*[num_preproc-1];
			preprocd= new bool[num_preproc-1];

			if (pps && preprocd)
			{
				int32_t j=0;
				for (int32_t i=0; i<num_preproc; i++)
				{
					if (i!=num)
					{
						pps[j]=preproc[i];
						preprocd[j]=preprocessed[i];
						j++;
					}
				}
			}
		}

		delete[] preproc;
		preproc=pps;
		delete[] preprocessed;
		preprocessed=preprocd;

		num_preproc--;

		for (int32_t i=0; i<num_preproc; i++)
			SG_INFO( "preproc[%d]=%s\n",i, preproc[i]->get_name()) ;
	}

	SG_UNREF(removed_preproc);
	return removed_preproc;
}

void CFeatures::list_feature_obj()
{
	SG_INFO( "%p - ", this);
	switch (get_feature_class())
	{
		case C_UNKNOWN:
			SG_INFO( "C_UNKNOWN ");
			break;
		case C_SIMPLE:
			SG_INFO( "C_SIMPLE ");
			break;
		case C_SPARSE:
			SG_INFO( "C_SPARSE ");
			break;
		case C_STRING:
			SG_INFO( "C_STRING ");
			break;
		case C_COMBINED:
			SG_INFO( "C_COMBINED ");
			break;
		case C_COMBINED_DOT:
			SG_INFO( "C_COMBINED_DOT ");
			break;
		case C_WD:
			SG_INFO( "C_WD ");
			break;
		case C_SPEC:
			SG_INFO( "C_SPEC ");
			break;
		case C_WEIGHTEDSPEC:
			SG_INFO( "C_WEIGHTEDSPEC ");
			break;
		case C_ANY:
			SG_INFO( "C_ANY ");
			break;
		default:
         SG_ERROR( "ERROR UNKNOWN FEATURE CLASS");
	}

	switch (get_feature_type())
	{
		case F_UNKNOWN:
			SG_INFO( "F_UNKNOWN \n");
			break;
		case F_CHAR:
			SG_INFO( "F_CHAR \n");
			break;
		case F_BYTE:
			SG_INFO( "F_BYTE \n");
			break;
		case F_SHORT:
			SG_INFO( "F_SHORT \n");
			break;
		case F_WORD:
			SG_INFO( "F_WORD \n");
			break;
		case F_INT:
			SG_INFO( "F_INT \n");
			break;
		case F_UINT:
			SG_INFO( "F_UINT \n");
			break;
		case F_LONG:
			SG_INFO( "F_LONG \n");
			break;
		case F_ULONG:
			SG_INFO( "F_ULONG \n");
			break;
		case F_SHORTREAL:
			SG_INFO( "F_SHORTEAL \n");
			break;
		case F_DREAL:
			SG_INFO( "F_DREAL \n");
			break;
		case F_LONGREAL:
			SG_INFO( "F_LONGREAL \n");
			break;
		case F_ANY:
			SG_INFO( "F_ANY \n");
			break;
		default:
         SG_ERROR( "ERROR UNKNOWN FEATURE TYPE\n");
	}
}

bool CFeatures::check_feature_compatibility(CFeatures* f)
{
	bool result=false;

	if (f)
		result= ( (this->get_feature_class() == f->get_feature_class()) &&
				(this->get_feature_type() == f->get_feature_type()));
	return result;
}

void CFeatures::set_feature_subset(int32_t subset_len, int32_t* subset_idx)
{
	if (m_subset_idx)
		delete[] m_subset_idx;

	m_subset_idx=subset_idx;
	m_subset_len=subset_len;
}

void CFeatures::set_feature_subset(int32_t* subset_idx, int32_t subset_len)
{
	ASSERT(subset_idx);

	delete[] m_subset_idx;
	m_subset_idx = NULL;

	int64_t length=sizeof(int32_t)*subset_len;

	m_subset_idx=(int32_t*) SG_MALLOC(length);

	memcpy(m_subset_idx, subset_idx, length);
}

void CFeatures::remove_feature_subset()
{
	if (!m_subset_idx)
	{
		delete[] m_subset_idx;
		m_subset_idx=NULL;
		m_subset_len=0;
	}
}

void CFeatures::get_feature_subset(int32_t** subset_idx, int32_t* subset_len)
{
	ASSERT(m_subset_idx);
	int64_t length = sizeof(int32_t)*m_subset_len;

	*subset_len=m_subset_len;
	*subset_idx=(int32_t*) SG_MALLOC(length);
s	memcpy(*subset_idx, m_subset_idx, length);
}
<|endoftext|>


<commit_before>/*

*/

#include "lineFollowing.h"
#include "../control.h"

using namespace std;
using namespace cv;

void compress_lines(vector<Vec2f> &condensed, const vector<Vec2f> &tmp_list);

void draw_lines(Mat &image, const vector<Vec2f> &lines);

vector<Vec2f> condense_lines(vector<Vec2f> lines, bool keep_going);

double deg2rad(double deg);

vector<Point> to_points(float theta, float rho);

bool parametricIntersect(float r1, float t1, float r2, float t2, int &x, int &y);

void LineFollowing::detect_lines(Mat &original_frame) {

  Mat hsv;
  Mat mask;
  width = original_frame.cols;
  height = original_frame.rows;

  cvtColor(original_frame, hsv, CV_BGR2HSV); // Image is now HSV

  Scalar lower(minH, minS, minV);
  Scalar upper(maxH, maxS, maxV);
  inRange(hsv, lower, upper, mask); // Create a mask of only the desired color
  Canny(mask, mask, 50, 200, 3);

  vector<Vec2f> lines;
  HoughLines(mask, lines, 1, CV_PI / 180, 100, 0, 0);

  // printf("Adding in %d lines\n", (int) lines.size());

  vector<Vec2f> tmp = condense_lines(lines, true);
  sort(tmp.begin(), tmp.end(),
       [](const Vec2f &a, const Vec2f &b) {
         return a[0] < b[0];
       });
  if (tmp.size() > 0) {
    found_lines = tmp;
  }

  draw_lines(original_frame, found_lines);

}

vector<Vec2f> condense_lines(vector<Vec2f> lines, bool keep_going) {
  vector<Vec2f> condensed;
  vector<Vec2f> tmp_list;
  double diff;
  for (int i = 0; i < (int) lines.size(); i++) {
    /*    if (lines[i][1] > CV_PI / 2) {
        lines[i][1] -= CV_PI;
        lines[i][0] *= -1;
      }
      else if (lines[i][1] < ((CV_PI / 2) * -1)) {
        lines[i][1] += CV_PI;
        lines[i][0] *= -1;
      }*/

    lines[i][1] -= deg2rad(360);

    while (lines[i][1] < 0) {
      lines[i][1] += deg2rad(360);
    }
    /*
      if (lines[i][1] >= deg2rad(90)) {
        lines[i][1] -= deg2rad(180);
        lines[i][0] *= -1;
      }
    */

    //put in order of theta, rho
    swap(lines[i][0], lines[i][1]);
  }

  //Order from least to greatest theta
  sort(lines.begin(), lines.end(),
       [](const Vec2f &a, const Vec2f &b) {
         return a[0] < b[0];
       });

  while (!lines.empty()) {
    Vec2f to_manipulate = lines.front();
    lines.erase(lines.begin());

    if (tmp_list.empty()) {
      tmp_list.push_back(to_manipulate);
      continue;
    } else {
      diff = abs(to_manipulate[0] - tmp_list.front()[0]);
      if (diff > deg2rad(180)) {
        diff = deg2rad(360) - diff;
      }
      if (diff < deg2rad(20)) {
        //The angles are similar
        if (abs(to_manipulate[1] - tmp_list.front()[1]) < 50) {
          //the distances are similar
          tmp_list.push_back(to_manipulate);
          continue;
        }
      } else {
        //Need to clear out the tmp_list
        compress_lines(condensed, tmp_list);

        tmp_list.clear();
        tmp_list.push_back(to_manipulate);

      }
    }
  }
  if (!tmp_list.empty()) {
    compress_lines(condensed, tmp_list);
  }

  condensed.back()[0] -= 360;
  if (keep_going) {
    condensed = condense_lines(condensed, false);
  }
  return condensed;
}

double deg2rad(double deg) {
  return deg * (CV_PI / 180.0);
}

double rad2deg(double rad) {
  return rad * (180.0 / CV_PI);
}

void draw_lines(Mat &image, const vector<Vec2f> &lines) {
  for (size_t i = 0; i < lines.size(); i++) {
    float theta = lines[i][0], rho = lines[i][1];
    // float rho = lines[i][0], theta = lines[i][1];Point pt1;
    vector<Point> p = to_points(theta, rho);
    line(image, p[0], p[1], Scalar(255 * (i == 0), 255 * (i == 1), 255 * (i == 2)), 3, CV_AA);
  }
}

vector<Point> to_points(float theta, float rho) {
  vector<Point> rv = {Point(), Point()};
  double a = cos(theta), b = sin(theta);
  double x0 = a * rho, y0 = b * rho;
  rv[0].x = cvRound(x0 + 1000 * (-b));
  rv[0].y = cvRound(y0 + 1000 * (a));
  rv[1].x = cvRound(x0 - 1000 * (-b));
  rv[1].y = cvRound(y0 - 1000 * (a));
  return rv;
}

void compress_lines(vector<Vec2f> &condensed, const vector<Vec2f> &tmp_list) {
  Vec2f new_point;
  float angle_sum = 0;
  float rho_sum = 0;
  for (int j = 0; j < (int) tmp_list.size(); ++j) {
    angle_sum += tmp_list[j][0];
    rho_sum += tmp_list[j][1];
  }
  angle_sum /= tmp_list.size();
  rho_sum /= tmp_list.size();

  new_point[0] = angle_sum;
  new_point[1] = rho_sum;

  condensed.push_back(new_point);
}

LineFollowing::LineFollowing(Control *control) {
  namedWindow("line_window", CV_WINDOW_NORMAL);
  control_ptr = control;
  minH = 50;
  minS = 20;
  minV = 150;
  maxH = 125;
  maxS = 100;
  maxV = 255;
  return;
}

void LineFollowing::close() {
  return;
}

void LineFollowing::fly() {
  // cout << "line following\n";
  detect_lines(control_ptr->image);

  control_ptr->velocities.vx = 0;
  control_ptr->velocities.vy = 0;
  control_ptr->velocities.vz = 0;
  control_ptr->velocities.vr = 0;

  if (found_lines.size() < 1) {
    //I found no lines
    // printf("Found nothing\n");
    return;
  }
  double calculated_distance = distance_from_center(found_lines[0][1], found_lines[0][0], control_ptr->image.cols,
                                                    control_ptr->image.rows);

  // printf("calc dist of %f ", calculated_distance);
  int origin_x = 0 + (control_ptr->image.cols / 2);
  int origin_y = 0 + (control_ptr->image.rows / 2);
  Point pt1 = cvPoint(origin_x, origin_y);
  Point pt2 = cvPoint(origin_x + cvRound(calculated_distance), origin_y);
  line(control_ptr->image, pt1, pt2, Scalar(0, 0, 255), 3, CV_AA);

  if (found_lines.size() > 1) {
    // I need to turn
    //TODO: move until line is centered
    //TODO: look for symbol, and turn
    origin_x = 0;
    origin_y = 0;
    Vec2i point = find_intersection(found_lines[0], found_lines[1]);
    //printf("My coords are x: %3d y %3d\n", point[0], point[1]);
    line(control_ptr->image, cvPoint(origin_x + point[0] + 10, origin_y + point[1]),
         cvPoint(origin_x + point[0] - 10, origin_y + point[1]), Scalar(0, 255, 0), 3, CV_AA);
    line(control_ptr->image, cvPoint(origin_x + point[0], origin_y + point[1] + 10),
         cvPoint(origin_x + point[0], origin_y + point[1] - 10), Scalar(0, 255, 0), 3, CV_AA);
    if (found_lines.size() >= 4) {
      for (int j = 0; j < (int) found_lines.size(); j++) {
        printf("theta: %.1f rho: %.0f  ", found_lines[j][0] * (180 / CV_PI), found_lines[j][1]);
      }
      printf("\n");
    }
    return;
  }

  else {
    // I need to snap myself to the line
    if (found_lines[0][0] >= deg2rad(5)) {
      control_ptr->velocities.vr = -.2;
      printf("Turning Right\n");
    }
    else if (found_lines[0][0] <= deg2rad(-1 * 5)) {
      control_ptr->velocities.vr = .2;
      printf("Turning Left\n");
    } else {
      printf("Checking Distance\n");

      double offset = calculated_distance;
      // printf("Offset is: %5.2f with a distance of %5.2f and width of %5.2f halved to %5.2f\n", offset,
      // found_lines[0][1],
      // (double) control_ptr->image.cols, (control_ptr->image.cols / 2.0));
      if (-100 <= offset && offset <= 100) {
        printf("No need to move\n");
      } else if (offset < 0) {
        //we are to the right of the line
        //we need to move left
        control_ptr->velocities.vy = 1;
        printf("Move left\n");
      } else {
        //we need to move right
        control_ptr->velocities.vy = -1;
        printf("Move right\n");
      }
    }
  }

  return;
}

double LineFollowing::distance_from_center(float rho, float theta, double width, double height) {
  // printf("width: %f height: %f\n", width, height);
  theta = -1 * (theta);
  double rh = rho * cos(theta);
  double rv = rho * sin(theta);
  // rh = abs(rh);
  // rv *= -1;
  double excess = (width / 2.0) - rh;
  // excess *=-1;
  double lv = rv + (height / 2.0);
  double lh = lv * tan(theta);
  // lh = abs(lh);
  double x = lh - excess;

  // printf("ro: %4f th: %4f rh: %4f rv: %4f ex: %4f lv: %4f lh: %4f x: %4f\n", rho, theta ,rh, rv, excess, lv,lh,x);

  return x;
}

cv::Point LineFollowing::find_intersection(Vec2f a, Vec2f b) {
  Point rv;
  bool do_intersect = parametricIntersect(a[1], a[0], b[1], b[0], rv.x, rv.y);
  if (!do_intersect) {
    printf("No intersection!\n");
  }

  return rv;
}

bool parametricIntersect(float r1, float t1, float r2, float t2, int &x, int &y) {
  float ct1 = cosf(t1);     //matrix element a
  float st1 = sinf(t1);     //b
  float ct2 = cosf(t2);     //c
  float st2 = sinf(t2);     //d
  float d = ct1 * st2 - st1 * ct2;        //determinative (rearranged matrix for inverse)
  if (d != 0.0f) {
    x = (int) ((st2 * r1 - st1 * r2) / d);
    y = (int) ((-ct2 * r1 + ct1 * r2) / d);
    return (true);
  } else { //lines are parallel and will NEVER intersect!
    return (false);
  }
}
<commit_msg>detects 3 lines robustly<commit_after>/*

*/

#include "lineFollowing.h"
#include "../control.h"

using namespace std;
using namespace cv;

double rad2deg(double rad);

void compress_lines(vector<Vec2f> &condensed, const vector<Vec2f> &tmp_list);

void draw_lines(Mat &image, const vector<Vec2f> &lines);

vector<Vec2f> condense_lines(vector<Vec2f> lines, bool keep_going);

double deg2rad(double deg);

vector<Point> to_points(float theta, float rho);

bool parametricIntersect(float r1, float t1, float r2, float t2, int &x, int &y);

void LineFollowing::detect_lines(Mat &original_frame) {

  Mat hsv;
  Mat mask;
  width = original_frame.cols;
  height = original_frame.rows;

  cvtColor(original_frame, hsv, CV_BGR2HSV); // Image is now HSV

  Scalar lower(minH, minS, minV);
  Scalar upper(maxH, maxS, maxV);
  inRange(hsv, lower, upper, mask); // Create a mask of only the desired color
  Canny(mask, mask, 50, 200, 3);

  vector<Vec2f> lines;
  HoughLines(mask, lines, 1, CV_PI / 180, 100, 0, 0);

  // printf("Adding in %d lines\n", (int) lines.size());

  vector<Vec2f> tmp = condense_lines(lines, true);
  sort(tmp.begin(), tmp.end(),
       [](const Vec2f &a, const Vec2f &b) {
         return a[0] < b[0];
       });
  if (tmp.size() > 0) {
    found_lines = tmp;
  }

  draw_lines(original_frame, found_lines);

}

vector<Vec2f> condense_lines(vector<Vec2f> lines, bool keep_going) {
  vector<Vec2f> condensed;
  vector<Vec2f> tmp_list;
  double diff;
  if (keep_going){
  for (int i = 0; i < (int) lines.size(); i++) {
    /*    if (lines[i][1] > CV_PI / 2) {
        lines[i][1] -= CV_PI;
        lines[i][0] *= -1;
      }
      else if (lines[i][1] < ((CV_PI / 2) * -1)) {
        lines[i][1] += CV_PI;
        lines[i][0] *= -1;
      }*/

    lines[i][1] -= deg2rad(360);

    while (lines[i][1] < 0) {
      lines[i][1] += deg2rad(360);
    }

      if (lines[i][1] >= deg2rad(90)) {
        lines[i][1] -= deg2rad(180);
        lines[i][0] *= -1;
      }

    //put in order of theta, rho
    swap(lines[i][0], lines[i][1]);

  }
  // return lines;
}
  //Order from least to greatest theta
  sort(lines.begin(), lines.end(),
       [](const Vec2f &a, const Vec2f &b) {
         return a[0] < b[0];
       });

  while (!lines.empty()) {
    Vec2f to_manipulate = lines.front();
    lines.erase(lines.begin());

    if (tmp_list.empty()) {
      tmp_list.push_back(to_manipulate);
      continue;
    } else {
      diff = abs(to_manipulate[0] - tmp_list.front()[0]);
      if (diff > deg2rad(180)) {
        diff = deg2rad(360) - diff;
      }
      if (diff < deg2rad(10)) {
        //The angles are similar
        if (abs(to_manipulate[1] - tmp_list.front()[1]) < 5) {
          //the distances are similar
          tmp_list.push_back(to_manipulate);
          continue;
        }
      } else {
        //Need to clear out the tmp_list
        compress_lines(condensed, tmp_list);

        tmp_list.clear();
        tmp_list.push_back(to_manipulate);

      }
    }
  }
  if (!tmp_list.empty()) {
    compress_lines(condensed, tmp_list);
  }
  if (condensed.size() >= 2)
  {
    // printf("changing %.1f", rad2deg(condensed.back()[0]));
  condensed.back()[0] -= deg2rad(180);
  condensed.back()[1] *= -1;
  // printf(" to %.1f\n", rad2deg(condensed.back()[0]));
  if (keep_going) {
    condensed = condense_lines(condensed, false);
  }
}
  return condensed;
}

double deg2rad(double deg) {
  return deg * (CV_PI / 180.0);
}

double rad2deg(double rad) {
  return rad * (180.0 / CV_PI);
}

void draw_lines(Mat &image, const vector<Vec2f> &lines) {
  for (size_t i = 0; i < lines.size(); i++) {
    float theta = lines[i][0], rho = lines[i][1];
    // float rho = lines[i][0], theta = lines[i][1];Point pt1;
    vector<Point> p = to_points(theta, rho);
    line(image, p[0], p[1], Scalar(255 * (i == 0), 255 * (i == 1), 255 * (i == 2)), 3, CV_AA);
  }
}

vector<Point> to_points(float theta, float rho) {
  vector<Point> rv = {Point(), Point()};
  double a = cos(theta), b = sin(theta);
  double x0 = a * rho, y0 = b * rho;
  rv[0].x = cvRound(x0 + 1000 * (-b));
  rv[0].y = cvRound(y0 + 1000 * (a));
  rv[1].x = cvRound(x0 - 1000 * (-b));
  rv[1].y = cvRound(y0 - 1000 * (a));
  return rv;
}

void compress_lines(vector<Vec2f> &condensed, const vector<Vec2f> &tmp_list) {
  Vec2f new_point;
  float angle_sum = 0;
  float rho_sum = 0;
  for (int j = 0; j < (int) tmp_list.size(); ++j) {
    angle_sum += tmp_list[j][0];
    rho_sum += tmp_list[j][1];
  }
  angle_sum /= tmp_list.size();
  rho_sum /= tmp_list.size();

  new_point[0] = angle_sum;
  new_point[1] = rho_sum;

  condensed.push_back(new_point);
}

LineFollowing::LineFollowing(Control *control) {
  namedWindow("line_window", CV_WINDOW_NORMAL);
  control_ptr = control;
  minH = 50;
  minS = 20;
  minV = 150;
  maxH = 125;
  maxS = 100;
  maxV = 255;
  return;
}

void LineFollowing::close() {
  return;
}

void LineFollowing::fly() {
  // cout << "line following\n";
  detect_lines(control_ptr->image);

  control_ptr->velocities.vx = 0;
  control_ptr->velocities.vy = 0;
  control_ptr->velocities.vz = 0;
  control_ptr->velocities.vr = 0;

  if (found_lines.size() < 1) {
    //I found no lines
    // printf("Found nothing\n");
    return;
  }
  double calculated_distance = distance_from_center(found_lines[0][1], found_lines[0][0], control_ptr->image.cols,
                                                    control_ptr->image.rows);

  // printf("calc dist of %f ", calculated_distance);
  int origin_x = 0 + (control_ptr->image.cols / 2);
  int origin_y = 0 + (control_ptr->image.rows / 2);
  Point pt1 = cvPoint(origin_x, origin_y);
  Point pt2 = cvPoint(origin_x + cvRound(calculated_distance), origin_y);
  line(control_ptr->image, pt1, pt2, Scalar(255, 255, 255), 3, CV_AA);

  if (found_lines.size() > 1) {
    // I need to turn
    //TODO: move until line is centered
    //TODO: look for symbol, and turn
    origin_x = 0;
    origin_y = 0;
    Vec2i point = find_intersection(found_lines[0], found_lines[1]);
    //printf("My coords are x: %3d y %3d\n", point[0], point[1]);
    line(control_ptr->image, cvPoint(origin_x + point[0] + 10, origin_y + point[1]),
         cvPoint(origin_x + point[0] - 10, origin_y + point[1]), Scalar(255, 255, 255), 3, CV_AA);
    line(control_ptr->image, cvPoint(origin_x + point[0], origin_y + point[1] + 10),
         cvPoint(origin_x + point[0], origin_y + point[1] - 10), Scalar(255, 255, 255), 3, CV_AA);
    if (found_lines.size() >= 3) {
      for (int j = 0; j < (int) found_lines.size(); j++) {
        printf("(%.1f, %.0f) ", rad2deg(found_lines[j][0]) + 90, found_lines[j][1]);
      }
      printf("\n");
    }
    return;
  }

  else {
    // I need to snap myself to the line
    if (found_lines[0][0] >= deg2rad(5)) {
      control_ptr->velocities.vr = -.2;
      // printf("Turning Right\n");
    }
    else if (found_lines[0][0] <= deg2rad(-1 * 5)) {
      control_ptr->velocities.vr = .2;
      // printf("Turning Left\n");
    } else {
      // printf("Checking Distance\n");

      double offset = calculated_distance;
      // printf("Offset is: %5.2f with a distance of %5.2f and width of %5.2f halved to %5.2f\n", offset,
      // found_lines[0][1],
      // (double) control_ptr->image.cols, (control_ptr->image.cols / 2.0));
      if (-100 <= offset && offset <= 100) {
        // printf("No need to move\n");
      } else if (offset < 0) {
        //we are to the right of the line
        //we need to move left
        control_ptr->velocities.vy = 1;
        // printf("Move left\n");
      } else {
        //we need to move right
        control_ptr->velocities.vy = -1;
        // printf("Move right\n");
      }
    }
  }

  return;
}

double LineFollowing::distance_from_center(float rho, float theta, double width, double height) {
  // printf("width: %f height: %f\n", width, height);
  theta = -1 * (theta);
  double rh = rho * cos(theta);
  double rv = rho * sin(theta);
  // rh = abs(rh);
  // rv *= -1;
  double excess = (width / 2.0) - rh;
  // excess *=-1;
  double lv = rv + (height / 2.0);
  double lh = lv * tan(theta);
  // lh = abs(lh);
  double x = lh - excess;

  // printf("ro: %4f th: %4f rh: %4f rv: %4f ex: %4f lv: %4f lh: %4f x: %4f\n", rho, theta ,rh, rv, excess, lv,lh,x);

  return x;
}

cv::Point LineFollowing::find_intersection(Vec2f a, Vec2f b) {
  Point rv;
  bool do_intersect = parametricIntersect(a[1], a[0], b[1], b[0], rv.x, rv.y);
  if (!do_intersect) {
    printf("No intersection!\n");
  }

  return rv;
}

bool parametricIntersect(float r1, float t1, float r2, float t2, int &x, int &y) {
  float ct1 = cosf(t1);     //matrix element a
  float st1 = sinf(t1);     //b
  float ct2 = cosf(t2);     //c
  float st2 = sinf(t2);     //d
  float d = ct1 * st2 - st1 * ct2;        //determinative (rearranged matrix for inverse)
  if (d != 0.0f) {
    x = (int) ((st2 * r1 - st1 * r2) / d);
    y = (int) ((-ct2 * r1 + ct1 * r2) / d);
    return (true);
  } else { //lines are parallel and will NEVER intersect!
    return (false);
  }
}
<|endoftext|>


<commit_before>/*

*/

#include "lineFollowing.h"

using namespace std;
using namespace cv;

void detect_lines(Mat &original_frame, double scale_factor);

#pragma clang diagnostic push
#pragma ide diagnostic ignored "OCUnusedGlobalDeclarationInspection"
void line_main() {
//  printf("Hello, this is Caleb\n");
//  no this is patric

  VideoCapture cap("../../tests/videos/top_down_1.m4v");
  if (!cap.isOpened())  // check if we succeeded
    return;

//  Mat edges;
  for (; ;) {
    Mat frame;
    cap >> frame; // get a new frame from camera

    detect_lines(frame, .2);

    if (waitKey(30) >= 0) break;

  }
  // the camera will be deinitialized automatically in VideoCapture destructor

  return;
}
#pragma clang diagnostic pop

void detect_lines(Mat &original_frame, double scale_factor) {
  Mat hsv;
  Mat mask;
  Mat image;

  resize(original_frame, image, Size(), scale_factor, scale_factor); //Potentially scale down the frame

  cvtColor(image, image, CV_BGR2HSV); // Image is now HSV

  double minH = 30;
  double minS = 0;
  double minV = 240;
  double maxH = 80;
  double maxS = 70;
  double maxV = 255;

  Scalar lower(minH, minS, minV);
  Scalar upper(maxH, maxS, maxV);
  inRange(image, lower, upper, mask); // Create a mask of only the desired color

  vector<Vec4i> lines;
  HoughLinesP(mask, lines, 1, CV_PI / 180.0, 10, 50, 10); // Find all lines in the image

  printf("Adding in %d lines\n", (int) lines.size());
  for (size_t i = 0; i < lines.size(); i++) {
    Vec4i l = lines[i];
    line(image, Point(l[0], l[1]), Point(l[2], l[3]), Scalar(0, 0, 255), 1, CV_AA);
    // break;
  }
//    if (lines.size() < 1) continue;

  imshow("line_window", original_frame);
}

void LineFollowing::initialize() {
  namedWindow("line_window", CV_WINDOW_NORMAL);
  return;
}

void LineFollowing::close() {
  return;
}

ControlMovements LineFollowing::fly(cv::Mat *image) {
  ControlMovements velocities;

  velocities.vx = 0;
  velocities.vy = 0;
  velocities.vz = 0;
  velocities.vr = 0;

  detect_lines(*image, 1);

  return velocities;
}
<commit_msg>"some" line detection<commit_after>/*

*/

#include "lineFollowing.h"

using namespace std;
using namespace cv;

void detect_lines(Mat &original_frame, double scale_factor);

#pragma clang diagnostic push
#pragma ide diagnostic ignored "OCUnusedGlobalDeclarationInspection"
void line_main() {
//  printf("Hello, this is Caleb\n");
//  no this is patric

  VideoCapture cap("../../tests/videos/top_down_1.m4v");
  if (!cap.isOpened())  // check if we succeeded
    return;

//  Mat edges;
  for (; ;) {
    Mat frame;
    cap >> frame; // get a new frame from camera

    detect_lines(frame, .2);

    if (waitKey(30) >= 0) break;

  }
  // the camera will be deinitialized automatically in VideoCapture destructor

  return;
}
#pragma clang diagnostic pop

void detect_lines(Mat &original_frame, double scale_factor) {
  Mat hsv;
  Mat mask;
  Mat image;

  resize(original_frame, image, Size(), scale_factor, scale_factor); //Potentially scale down the frame

  cvtColor(image, hsv, CV_BGR2HSV); // Image is now HSV

  double minH = 50;
  double minS = 20;
  double minV = 150;
  double maxH = 125;
  double maxS = 100;
  double maxV = 255;

  Scalar lower(minH, minS, minV);
  Scalar upper(maxH, maxS, maxV);
  inRange(hsv, lower, upper, mask); // Create a mask of only the desired color

  vector<Vec4i> lines;
  HoughLinesP(mask, lines, 1, CV_PI / 180.0, 10, 50, 10); // Find all lines in the image

  printf("Adding in %d lines\n", (int) lines.size());
  for (size_t i = 0; i < lines.size(); i++) {
    Vec4i l = lines[i];
    line(image, Point(l[0], l[1]), Point(l[2], l[3]), Scalar(0, 0, 255), 1, CV_AA);
    // break;
  }
//    if (lines.size() < 1) continue;

  imshow("line_window", image);
}

void LineFollowing::initialize() {
  namedWindow("line_window", CV_WINDOW_NORMAL);
  return;
}

void LineFollowing::close() {
  return;
}

ControlMovements LineFollowing::fly(cv::Mat *image) {
  ControlMovements velocities;

  velocities.vx = 0;
  velocities.vy = 0;
  velocities.vz = 0;
  velocities.vr = 0;

  detect_lines(*image, .3);

  return velocities;
}
<|endoftext|>


<commit_before>//===--- IndexerMain.cpp -----------------------------------------*- C++-*-===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// GlobalSymbolBuilder is a tool to extract symbols from a whole project.
// This tool is **experimental** only. Don't use it in production code.
//
//===----------------------------------------------------------------------===//

#include "index/Index.h"
#include "index/IndexAction.h"
#include "index/Merge.h"
#include "index/Serialization.h"
#include "index/SymbolCollector.h"
#include "clang/Tooling/CommonOptionsParser.h"
#include "clang/Tooling/Execution.h"
#include "clang/Tooling/Tooling.h"
#include "llvm/Support/CommandLine.h"
#include "llvm/Support/Path.h"
#include "llvm/Support/Signals.h"

using namespace llvm;
using namespace clang::tooling;
using clang::clangd::SymbolSlab;

namespace clang {
namespace clangd {
namespace {

static llvm::cl::opt<std::string> AssumedHeaderDir(
    "assume-header-dir",
    llvm::cl::desc("The index includes header that a symbol is defined in. "
                   "If the absolute path cannot be determined (e.g. an "
                   "in-memory VFS) then the relative path is resolved against "
                   "this directory, which must be absolute. If this flag is "
                   "not given, such headers will have relative paths."),
    llvm::cl::init(""));

static llvm::cl::opt<IndexFileFormat>
    Format("format", llvm::cl::desc("Format of the index to be written"),
           llvm::cl::values(clEnumValN(IndexFileFormat::YAML, "yaml",
                                       "human-readable YAML format"),
                            clEnumValN(IndexFileFormat::RIFF, "binary",
                                       "binary RIFF format")),
           llvm::cl::init(IndexFileFormat::YAML));

class IndexActionFactory : public tooling::FrontendActionFactory {
public:
  IndexActionFactory(IndexFileIn &Result) : Result(Result) {}

  clang::FrontendAction *create() override {
    SymbolCollector::Options Opts;
    Opts.FallbackDir = AssumedHeaderDir;
    return createStaticIndexingAction(
               Opts,
               [&](SymbolSlab S) {
                 // Merge as we go.
                 std::lock_guard<std::mutex> Lock(SymbolsMu);
                 for (const auto &Sym : S) {
                   if (const auto *Existing = Symbols.find(Sym.ID))
                     Symbols.insert(mergeSymbol(*Existing, Sym));
                   else
                     Symbols.insert(Sym);
                 }
               },
               [&](RefSlab S) {
                 std::lock_guard<std::mutex> Lock(SymbolsMu);
                 for (const auto &Sym : S) {
                   // No need to merge as currently all Refs are from main file.
                   for (const auto &Ref : Sym.second)
                     Refs.insert(Sym.first, Ref);
                 }
               })
        .release();
  }

  // Awkward: we write the result in the destructor, because the executor
  // takes ownership so it's the easiest way to get our data back out.
  ~IndexActionFactory() {
    Result.Symbols = std::move(Symbols).build();
    Result.Refs = std::move(Refs).build();
  }

private:
  IndexFileIn &Result;
  std::mutex SymbolsMu;
  SymbolSlab::Builder Symbols;
  RefSlab::Builder Refs;
};

} // namespace
} // namespace clangd
} // namespace clang

int main(int argc, const char **argv) {
  llvm::sys::PrintStackTraceOnErrorSignal(argv[0]);

  const char *Overview = R"(
  Creates an index of symbol information etc in a whole project.
  This is **experimental** and not production-ready!

  Example usage for a project using CMake compile commands:

  $ clangd-indexer --executor=all-TUs compile_commands.json > index.yaml

  Example usage for file sequence index without flags:

  $ clangd-indexer File1.cpp File2.cpp ... FileN.cpp > index.yaml

  Note: only symbols from header files will be indexed.
  )";

  auto Executor = clang::tooling::createExecutorFromCommandLineArgs(
      argc, argv, cl::GeneralCategory, Overview);

  if (!Executor) {
    llvm::errs() << llvm::toString(Executor.takeError()) << "\n";
    return 1;
  }

  if (!clang::clangd::AssumedHeaderDir.empty() &&
      !llvm::sys::path::is_absolute(clang::clangd::AssumedHeaderDir)) {
    llvm::errs() << "--assume-header-dir must be an absolute path.\n";
    return 1;
  }

  // Collect symbols found in each translation unit, merging as we go.
  clang::clangd::IndexFileIn Data;
  auto Err = Executor->get()->execute(
      llvm::make_unique<clang::clangd::IndexActionFactory>(Data));
  if (Err) {
    llvm::errs() << llvm::toString(std::move(Err)) << "\n";
  }

  // Emit collected data.
  clang::clangd::IndexFileOut Out(Data);
  Out.Format = clang::clangd::Format;
  llvm::outs() << Out;
  return 0;
}
<commit_msg>[clangd] Make binary index format the default, remove dead flag.<commit_after>//===--- IndexerMain.cpp -----------------------------------------*- C++-*-===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// clangd-indexer is a tool to gather index data (symbols, xrefs) from source.
//
//===----------------------------------------------------------------------===//

#include "index/Index.h"
#include "index/IndexAction.h"
#include "index/Merge.h"
#include "index/Serialization.h"
#include "index/SymbolCollector.h"
#include "clang/Tooling/CommonOptionsParser.h"
#include "clang/Tooling/Execution.h"
#include "clang/Tooling/Tooling.h"
#include "llvm/Support/CommandLine.h"
#include "llvm/Support/Signals.h"

using namespace llvm;
using namespace clang::tooling;
using clang::clangd::SymbolSlab;

namespace clang {
namespace clangd {
namespace {

static llvm::cl::opt<IndexFileFormat>
    Format("format", llvm::cl::desc("Format of the index to be written"),
           llvm::cl::values(clEnumValN(IndexFileFormat::YAML, "yaml",
                                       "human-readable YAML format"),
                            clEnumValN(IndexFileFormat::RIFF, "binary",
                                       "binary RIFF format")),
           llvm::cl::init(IndexFileFormat::RIFF));

class IndexActionFactory : public tooling::FrontendActionFactory {
public:
  IndexActionFactory(IndexFileIn &Result) : Result(Result) {}

  clang::FrontendAction *create() override {
    SymbolCollector::Options Opts;
    return createStaticIndexingAction(
               Opts,
               [&](SymbolSlab S) {
                 // Merge as we go.
                 std::lock_guard<std::mutex> Lock(SymbolsMu);
                 for (const auto &Sym : S) {
                   if (const auto *Existing = Symbols.find(Sym.ID))
                     Symbols.insert(mergeSymbol(*Existing, Sym));
                   else
                     Symbols.insert(Sym);
                 }
               },
               [&](RefSlab S) {
                 std::lock_guard<std::mutex> Lock(SymbolsMu);
                 for (const auto &Sym : S) {
                   // No need to merge as currently all Refs are from main file.
                   for (const auto &Ref : Sym.second)
                     Refs.insert(Sym.first, Ref);
                 }
               })
        .release();
  }

  // Awkward: we write the result in the destructor, because the executor
  // takes ownership so it's the easiest way to get our data back out.
  ~IndexActionFactory() {
    Result.Symbols = std::move(Symbols).build();
    Result.Refs = std::move(Refs).build();
  }

private:
  IndexFileIn &Result;
  std::mutex SymbolsMu;
  SymbolSlab::Builder Symbols;
  RefSlab::Builder Refs;
};

} // namespace
} // namespace clangd
} // namespace clang

int main(int argc, const char **argv) {
  llvm::sys::PrintStackTraceOnErrorSignal(argv[0]);

  const char *Overview = R"(
  Creates an index of symbol information etc in a whole project.

  Example usage for a project using CMake compile commands:

  $ clangd-indexer --executor=all-TUs compile_commands.json > clangd.dex

  Example usage for file sequence index without flags:

  $ clangd-indexer File1.cpp File2.cpp ... FileN.cpp > clangd.dex

  Note: only symbols from header files will be indexed.
  )";

  auto Executor = clang::tooling::createExecutorFromCommandLineArgs(
      argc, argv, cl::GeneralCategory, Overview);

  if (!Executor) {
    llvm::errs() << llvm::toString(Executor.takeError()) << "\n";
    return 1;
  }

  // Collect symbols found in each translation unit, merging as we go.
  clang::clangd::IndexFileIn Data;
  auto Err = Executor->get()->execute(
      llvm::make_unique<clang::clangd::IndexActionFactory>(Data));
  if (Err) {
    llvm::errs() << llvm::toString(std::move(Err)) << "\n";
  }

  // Emit collected data.
  clang::clangd::IndexFileOut Out(Data);
  Out.Format = clang::clangd::Format;
  llvm::outs() << Out;
  return 0;
}
<|endoftext|>


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

#include "GafferOSL/OSLObject.h"

#include "GafferOSL/OSLShader.h"
#include "GafferOSL/ShadingEngine.h"

#include "GafferScene/ResamplePrimitiveVariables.h"

#include "IECoreScene/Primitive.h"

using namespace Imath;
using namespace IECore;
using namespace IECoreScene;
using namespace Gaffer;
using namespace GafferScene;
using namespace GafferOSL;

IE_CORE_DEFINERUNTIMETYPED( OSLObject );

size_t OSLObject::g_firstPlugIndex;

namespace
{

CompoundDataPtr prepareShadingPoints( const Primitive *primitive, const ShadingEngine *shadingEngine )
{
	CompoundDataPtr shadingPoints = new CompoundData;
	for( PrimitiveVariableMap::const_iterator it = primitive->variables.begin(), eIt = primitive->variables.end(); it != eIt; ++it )
	{
		// todo: consider passing something like IndexedView to the ShadingEngine to avoid the expansion of indexed data.
		if( shadingEngine->needsAttribute( it->first ) )
		{
			if( it->second.indices )
			{
				shadingPoints->writable()[it->first] = it->second.expandedData();
			}
			else
			{
				shadingPoints->writable()[it->first] = boost::const_pointer_cast<Data>( it->second.data );
			}
		}
	}

	return shadingPoints;
}

};

OSLObject::OSLObject( const std::string &name )
	:	SceneElementProcessor( name, IECore::PathMatcher::NoMatch )
{
	storeIndexOfNextChild( g_firstPlugIndex );
	addChild( new ShaderPlug( "shader" ) );
	addChild( new IntPlug( "interpolation", Plug::In, PrimitiveVariable::Vertex, PrimitiveVariable::Invalid, PrimitiveVariable::FaceVarying ) );
	addChild( new ScenePlug( "__resampledIn", Plug::In, Plug::Default & ~Plug::Serialisable ) );

	addChild( new StringPlug( "__resampleNames", Plug::Out ) );

	GafferScene::ResamplePrimitiveVariablesPtr resample = new ResamplePrimitiveVariables( "__resample" );
	addChild( resample );

	//todo only resample variables which we've read from in the OSL shader
	resample->namesPlug()->setInput( resampledNamesPlug() );
	resample->inPlug()->setInput( inPlug() );
	resample->interpolationPlug()->setInput( interpolationPlug() );
	resample->filterPlug()->setInput( filterPlug() );

	resampledInPlug()->setInput( resample->outPlug() );

	// Pass-throughs for things we don't want to modify
	outPlug()->attributesPlug()->setInput( inPlug()->attributesPlug() );
	outPlug()->transformPlug()->setInput( inPlug()->transformPlug() );
}

OSLObject::~OSLObject()
{
}

GafferScene::ShaderPlug *OSLObject::shaderPlug()
{
	return getChild<ShaderPlug>( g_firstPlugIndex );
}

const GafferScene::ShaderPlug *OSLObject::shaderPlug() const
{
	return getChild<ShaderPlug>( g_firstPlugIndex );
}

Gaffer::IntPlug *OSLObject::interpolationPlug()
{
	return getChild<IntPlug>( g_firstPlugIndex + 1 );
}

const Gaffer::IntPlug *OSLObject::interpolationPlug() const
{
	return getChild<IntPlug>( g_firstPlugIndex + 1 );
}

ScenePlug *OSLObject::resampledInPlug()
{
	return getChild<ScenePlug>( g_firstPlugIndex + 2 );
}

const ScenePlug *OSLObject::resampledInPlug() const
{
	return getChild<ScenePlug>( g_firstPlugIndex + 2 );
}

StringPlug *OSLObject::resampledNamesPlug()
{
	return getChild<StringPlug>( g_firstPlugIndex + 3 );
}

const StringPlug *OSLObject::resampledNamesPlug() const
{
	return getChild<StringPlug>( g_firstPlugIndex + 3 );
}

void OSLObject::affects( const Gaffer::Plug *input, AffectedPlugsContainer &outputs ) const
{
	SceneElementProcessor::affects( input, outputs );

	if(
		input == shaderPlug() ||
		input == inPlug()->transformPlug() ||
		input == interpolationPlug() ||
		input == resampledInPlug()->objectPlug()
	)
	{
		outputs.push_back( outPlug()->objectPlug() );
	}

	if(
		input == shaderPlug() ||
		input == inPlug()->objectPlug() ||
	)
	{
		outputs.push_back( resampledNamesPlug() );
	}

	if( input == outPlug()->objectPlug() )
	{
		outputs.push_back( outPlug()->boundPlug() );
	}
}

bool OSLObject::acceptsInput( const Gaffer::Plug *plug, const Gaffer::Plug *inputPlug ) const
{
	if( !SceneElementProcessor::acceptsInput( plug, inputPlug ) )
	{
		return false;
	}

	if( !inputPlug )
	{
		return true;
	}

	if( plug == shaderPlug() )
	{
		if( const GafferScene::Shader *shader = runTimeCast<const GafferScene::Shader>( inputPlug->source()->node() ) )
		{
			const OSLShader *oslShader = runTimeCast<const OSLShader>( shader );
			return oslShader && oslShader->typePlug()->getValue() == "osl:surface";
		}
	}

	return true;
}

bool OSLObject::processesBound() const
{
	return runTimeCast<const OSLShader>( shaderPlug()->source()->node() );
}

void OSLObject::hashProcessedBound( const ScenePath &path, const Gaffer::Context *context, IECore::MurmurHash &h ) const
{
	hashProcessedObject( path, context, h );
}

Imath::Box3f OSLObject::computeProcessedBound( const ScenePath &path, const Gaffer::Context *context, const Imath::Box3f &inputBound ) const
{
	ConstObjectPtr object = outPlug()->objectPlug()->getValue();
	if( const Primitive *primitive = runTimeCast<const Primitive>( object.get() ) )
	{
		return primitive->bound();
	}
	return inputBound;
}

bool OSLObject::processesObject() const
{
	return runTimeCast<const OSLShader>( shaderPlug()->source()->node() );
}

void OSLObject::hashProcessedObject( const ScenePath &path, const Gaffer::Context *context, IECore::MurmurHash &h ) const
{
	const OSLShader *shader = runTimeCast<const OSLShader>( shaderPlug()->source()->node() );
	ConstShadingEnginePtr shadingEngine = shader ? shader->shadingEngine() : nullptr;

	if( !shadingEngine )
	{
		return;
	}

	shadingEngine->hash( h );
	interpolationPlug()->hash( h );
	h.append( inPlug()->fullTransformHash( path ) );
	h.append( resampledInPlug()->objectPlug()->hash() );
}

static const IECore::InternedString g_world("world");

IECore::ConstObjectPtr OSLObject::computeProcessedObject( const ScenePath &path, const Gaffer::Context *context, IECore::ConstObjectPtr inputObject ) const
{
	const Primitive *inputPrimitive = runTimeCast<const Primitive>( inputObject.get() );
	if( !inputPrimitive )
	{
		return inputObject;
	}

	const OSLShader *shader = runTimeCast<const OSLShader>( shaderPlug()->source()->node() );
	ConstShadingEnginePtr shadingEngine = shader ? shader->shadingEngine() : nullptr;

	if( !shadingEngine )
	{
		return inputObject;
	}

	PrimitiveVariable::Interpolation interpolation = static_cast<PrimitiveVariable::Interpolation>( interpolationPlug()->getValue() );

	IECoreScene::ConstPrimitivePtr resampledObject = IECore::runTimeCast<const IECoreScene::Primitive>( resampledInPlug()->objectPlug()->getValue() );
	CompoundDataPtr shadingPoints = prepareShadingPoints( resampledObject.get(), shadingEngine.get() );

	PrimitivePtr outputPrimitive = inputPrimitive->copy();

	ShadingEngine::Transforms transforms;

	transforms[ g_world ] = ShadingEngine::Transform( inPlug()->fullTransform( path ));

	CompoundDataPtr shadedPoints = shadingEngine->shade( shadingPoints.get(), transforms );
	for( CompoundDataMap::const_iterator it = shadedPoints->readable().begin(), eIt = shadedPoints->readable().end(); it != eIt; ++it )
	{

		// Ignore the output color closure as the debug closures are used to define what is 'exported' from the shader
		if( it->first != "Ci" )
		{
			outputPrimitive->variables[it->first] = PrimitiveVariable( interpolation, it->second );
		}
	}

	return outputPrimitive;
}

void OSLObject::hash( const ValuePlug *output, const Context *context, IECore::MurmurHash &h ) const
{
	SceneElementProcessor::hash( output, context, h );

	if( output == resampledNamesPlug() )
	{
		inPlug()->objectPlug()->hash( h );
		h.append( shaderPlug()->attributesHash() );
	}
}

void OSLObject::compute( Gaffer::ValuePlug *output, const Gaffer::Context *context ) const
{
	if( output == resampledNamesPlug() )
	{
		ConstPrimitivePtr prim = runTimeCast<const IECoreScene::Primitive>( inPlug()->objectPlug()->getValue() );

		if (!prim)
		{
			static_cast<StringPlug *>( output )->setToDefault();
			return;
		}

		std::string primitiveVariablesToResample;

		const OSLShader *shader = runTimeCast<const OSLShader>( shaderPlug()->source()->node() );
		ConstShadingEnginePtr shadingEngine = shader ? shader->shadingEngine() : nullptr;

		for( PrimitiveVariableMap::const_iterator it = prim->variables.begin(); it != prim->variables.end(); ++it )
		{
			if( it->second.interpolation == PrimitiveVariable::Constant )
			{
				continue;
			}

			if( shadingEngine && !shadingEngine->needsAttribute( it->first ) )
			{
				continue;
			}

			primitiveVariablesToResample += " " + it->first;
		}

		static_cast<StringPlug *>( output )->setValue( primitiveVariablesToResample );
		return;
	}

	SceneElementProcessor::compute( output, context );
}
<commit_msg>OSLObject : Remove todo<commit_after>//////////////////////////////////////////////////////////////////////////
//
//  Copyright (c) 2013, John Haddon. All rights reserved.
//
//  Redistribution and use in source and binary forms, with or without
//  modification, are permitted provided that the following conditions are
//  met:
//
//      * Redistributions of source code must retain the above
//        copyright notice, this list of conditions and the following
//        disclaimer.
//
//      * Redistributions in binary form must reproduce the above
//        copyright notice, this list of conditions and the following
//        disclaimer in the documentation and/or other materials provided with
//        the distribution.
//
//      * Neither the name of John Haddon nor the names of
//        any other contributors to this software may be used to endorse or
//        promote products derived from this software without specific prior
//        written permission.
//
//  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
//  IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
//  THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
//  PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
//  CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
//  EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
//  PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
//  PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
//  LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
//  NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
//  SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//
//////////////////////////////////////////////////////////////////////////

#include "GafferOSL/OSLObject.h"

#include "GafferOSL/OSLShader.h"
#include "GafferOSL/ShadingEngine.h"

#include "GafferScene/ResamplePrimitiveVariables.h"

#include "IECoreScene/Primitive.h"

using namespace Imath;
using namespace IECore;
using namespace IECoreScene;
using namespace Gaffer;
using namespace GafferScene;
using namespace GafferOSL;

IE_CORE_DEFINERUNTIMETYPED( OSLObject );

size_t OSLObject::g_firstPlugIndex;

namespace
{

CompoundDataPtr prepareShadingPoints( const Primitive *primitive, const ShadingEngine *shadingEngine )
{
	CompoundDataPtr shadingPoints = new CompoundData;
	for( PrimitiveVariableMap::const_iterator it = primitive->variables.begin(), eIt = primitive->variables.end(); it != eIt; ++it )
	{
		// todo: consider passing something like IndexedView to the ShadingEngine to avoid the expansion of indexed data.
		if( shadingEngine->needsAttribute( it->first ) )
		{
			if( it->second.indices )
			{
				shadingPoints->writable()[it->first] = it->second.expandedData();
			}
			else
			{
				shadingPoints->writable()[it->first] = boost::const_pointer_cast<Data>( it->second.data );
			}
		}
	}

	return shadingPoints;
}

};

OSLObject::OSLObject( const std::string &name )
	:	SceneElementProcessor( name, IECore::PathMatcher::NoMatch )
{
	storeIndexOfNextChild( g_firstPlugIndex );
	addChild( new ShaderPlug( "shader" ) );
	addChild( new IntPlug( "interpolation", Plug::In, PrimitiveVariable::Vertex, PrimitiveVariable::Invalid, PrimitiveVariable::FaceVarying ) );
	addChild( new ScenePlug( "__resampledIn", Plug::In, Plug::Default & ~Plug::Serialisable ) );

	addChild( new StringPlug( "__resampleNames", Plug::Out ) );

	GafferScene::ResamplePrimitiveVariablesPtr resample = new ResamplePrimitiveVariables( "__resample" );
	addChild( resample );

	resample->namesPlug()->setInput( resampledNamesPlug() );
	resample->inPlug()->setInput( inPlug() );
	resample->interpolationPlug()->setInput( interpolationPlug() );
	resample->filterPlug()->setInput( filterPlug() );

	resampledInPlug()->setInput( resample->outPlug() );

	// Pass-throughs for things we don't want to modify
	outPlug()->attributesPlug()->setInput( inPlug()->attributesPlug() );
	outPlug()->transformPlug()->setInput( inPlug()->transformPlug() );
}

OSLObject::~OSLObject()
{
}

GafferScene::ShaderPlug *OSLObject::shaderPlug()
{
	return getChild<ShaderPlug>( g_firstPlugIndex );
}

const GafferScene::ShaderPlug *OSLObject::shaderPlug() const
{
	return getChild<ShaderPlug>( g_firstPlugIndex );
}

Gaffer::IntPlug *OSLObject::interpolationPlug()
{
	return getChild<IntPlug>( g_firstPlugIndex + 1 );
}

const Gaffer::IntPlug *OSLObject::interpolationPlug() const
{
	return getChild<IntPlug>( g_firstPlugIndex + 1 );
}

ScenePlug *OSLObject::resampledInPlug()
{
	return getChild<ScenePlug>( g_firstPlugIndex + 2 );
}

const ScenePlug *OSLObject::resampledInPlug() const
{
	return getChild<ScenePlug>( g_firstPlugIndex + 2 );
}

StringPlug *OSLObject::resampledNamesPlug()
{
	return getChild<StringPlug>( g_firstPlugIndex + 3 );
}

const StringPlug *OSLObject::resampledNamesPlug() const
{
	return getChild<StringPlug>( g_firstPlugIndex + 3 );
}

void OSLObject::affects( const Gaffer::Plug *input, AffectedPlugsContainer &outputs ) const
{
	SceneElementProcessor::affects( input, outputs );

	if(
		input == shaderPlug() ||
		input == inPlug()->transformPlug() ||
		input == interpolationPlug() ||
		input == resampledInPlug()->objectPlug()
	)
	{
		outputs.push_back( outPlug()->objectPlug() );
	}

	if(
		input == shaderPlug() ||
		input == inPlug()->objectPlug() ||
	)
	{
		outputs.push_back( resampledNamesPlug() );
	}

	if( input == outPlug()->objectPlug() )
	{
		outputs.push_back( outPlug()->boundPlug() );
	}
}

bool OSLObject::acceptsInput( const Gaffer::Plug *plug, const Gaffer::Plug *inputPlug ) const
{
	if( !SceneElementProcessor::acceptsInput( plug, inputPlug ) )
	{
		return false;
	}

	if( !inputPlug )
	{
		return true;
	}

	if( plug == shaderPlug() )
	{
		if( const GafferScene::Shader *shader = runTimeCast<const GafferScene::Shader>( inputPlug->source()->node() ) )
		{
			const OSLShader *oslShader = runTimeCast<const OSLShader>( shader );
			return oslShader && oslShader->typePlug()->getValue() == "osl:surface";
		}
	}

	return true;
}

bool OSLObject::processesBound() const
{
	return runTimeCast<const OSLShader>( shaderPlug()->source()->node() );
}

void OSLObject::hashProcessedBound( const ScenePath &path, const Gaffer::Context *context, IECore::MurmurHash &h ) const
{
	hashProcessedObject( path, context, h );
}

Imath::Box3f OSLObject::computeProcessedBound( const ScenePath &path, const Gaffer::Context *context, const Imath::Box3f &inputBound ) const
{
	ConstObjectPtr object = outPlug()->objectPlug()->getValue();
	if( const Primitive *primitive = runTimeCast<const Primitive>( object.get() ) )
	{
		return primitive->bound();
	}
	return inputBound;
}

bool OSLObject::processesObject() const
{
	return runTimeCast<const OSLShader>( shaderPlug()->source()->node() );
}

void OSLObject::hashProcessedObject( const ScenePath &path, const Gaffer::Context *context, IECore::MurmurHash &h ) const
{
	const OSLShader *shader = runTimeCast<const OSLShader>( shaderPlug()->source()->node() );
	ConstShadingEnginePtr shadingEngine = shader ? shader->shadingEngine() : nullptr;

	if( !shadingEngine )
	{
		return;
	}

	shadingEngine->hash( h );
	interpolationPlug()->hash( h );
	h.append( inPlug()->fullTransformHash( path ) );
	h.append( resampledInPlug()->objectPlug()->hash() );
}

static const IECore::InternedString g_world("world");

IECore::ConstObjectPtr OSLObject::computeProcessedObject( const ScenePath &path, const Gaffer::Context *context, IECore::ConstObjectPtr inputObject ) const
{
	const Primitive *inputPrimitive = runTimeCast<const Primitive>( inputObject.get() );
	if( !inputPrimitive )
	{
		return inputObject;
	}

	const OSLShader *shader = runTimeCast<const OSLShader>( shaderPlug()->source()->node() );
	ConstShadingEnginePtr shadingEngine = shader ? shader->shadingEngine() : nullptr;

	if( !shadingEngine )
	{
		return inputObject;
	}

	PrimitiveVariable::Interpolation interpolation = static_cast<PrimitiveVariable::Interpolation>( interpolationPlug()->getValue() );

	IECoreScene::ConstPrimitivePtr resampledObject = IECore::runTimeCast<const IECoreScene::Primitive>( resampledInPlug()->objectPlug()->getValue() );
	CompoundDataPtr shadingPoints = prepareShadingPoints( resampledObject.get(), shadingEngine.get() );

	PrimitivePtr outputPrimitive = inputPrimitive->copy();

	ShadingEngine::Transforms transforms;

	transforms[ g_world ] = ShadingEngine::Transform( inPlug()->fullTransform( path ));

	CompoundDataPtr shadedPoints = shadingEngine->shade( shadingPoints.get(), transforms );
	for( CompoundDataMap::const_iterator it = shadedPoints->readable().begin(), eIt = shadedPoints->readable().end(); it != eIt; ++it )
	{

		// Ignore the output color closure as the debug closures are used to define what is 'exported' from the shader
		if( it->first != "Ci" )
		{
			outputPrimitive->variables[it->first] = PrimitiveVariable( interpolation, it->second );
		}
	}

	return outputPrimitive;
}

void OSLObject::hash( const ValuePlug *output, const Context *context, IECore::MurmurHash &h ) const
{
	SceneElementProcessor::hash( output, context, h );

	if( output == resampledNamesPlug() )
	{
		inPlug()->objectPlug()->hash( h );
		h.append( shaderPlug()->attributesHash() );
	}
}

void OSLObject::compute( Gaffer::ValuePlug *output, const Gaffer::Context *context ) const
{
	if( output == resampledNamesPlug() )
	{
		ConstPrimitivePtr prim = runTimeCast<const IECoreScene::Primitive>( inPlug()->objectPlug()->getValue() );

		if (!prim)
		{
			static_cast<StringPlug *>( output )->setToDefault();
			return;
		}

		std::string primitiveVariablesToResample;

		const OSLShader *shader = runTimeCast<const OSLShader>( shaderPlug()->source()->node() );
		ConstShadingEnginePtr shadingEngine = shader ? shader->shadingEngine() : nullptr;

		for( PrimitiveVariableMap::const_iterator it = prim->variables.begin(); it != prim->variables.end(); ++it )
		{
			if( it->second.interpolation == PrimitiveVariable::Constant )
			{
				continue;
			}

			if( shadingEngine && !shadingEngine->needsAttribute( it->first ) )
			{
				continue;
			}

			primitiveVariablesToResample += " " + it->first;
		}

		static_cast<StringPlug *>( output )->setValue( primitiveVariablesToResample );
		return;
	}

	SceneElementProcessor::compute( output, context );
}
<|endoftext|>


<commit_before>/**
 * @file nca_main.cpp
 * @author Ryan Curtin
 *
 * Executable for Neighborhood Components Analysis.
 */
#include <mlpack/core.hpp>
#include <mlpack/core/metrics/lmetric.hpp>

#include "nca.hpp"

// Define parameters.
PROGRAM_INFO("Neighborhood Components Analysis (NCA)",
    "This program implements Neighborhood Components Analysis, both a linear "
    "dimensionality reduction technique and a distance learning technique.  The"
    " method seeks to improve k-nearest-neighbor classification on a dataset "
    "by scaling the dimensions.  The method is nonparametric, and does not "
    "require a value of k.  It works by using stochastic (\"soft\") neighbor "
    "assignments and using optimization techniques over the gradient of the "
    "accuracy of the neighbor assignments.\n"
    "\n"
    "To work, this algorithm needs labeled data.  It can be given as the last "
    "row of the input dataset (--input_file), or alternatively in a separate "
    "file (--labels_file).");

PARAM_STRING_REQ("input_file", "Input dataset to run NCA on.", "i");
PARAM_STRING_REQ("output_file", "Output file for learned distance matrix.",
    "o");
PARAM_STRING("labels_file", "File of labels for input dataset.", "l", "");
PARAM_DOUBLE("step_size", "Step size for stochastic gradient descent (alpha).",
    "a", 0.01);
PARAM_INT("max_iterations", "Maximum number of iterations for stochastic "
    "gradient descent (0 indicates no limit).", "n", 500000);
PARAM_DOUBLE("tolerance", "Maximum tolerance for termination of stochastic "
    "gradient descent.", "t", 1e-7);
PARAM_FLAG("normalize", "Use a normalized starting point for optimization. This"
    " is useful for when points are far apart, or when SGD is returning NaN.",
    "N");
PARAM_INT("seed", "Random seed.  If 0, 'std::time(NULL)' is used.", "s", 0);
PARAM_FLAG("linear_scan", "Don't shuffle the order in which data points are "
    "visited for SGD.", "L");

using namespace mlpack;
using namespace mlpack::nca;
using namespace mlpack::metric;
using namespace std;
using namespace arma;

int main(int argc, char* argv[])
{
  // Parse command line.
  CLI::ParseCommandLine(argc, argv);

  if (CLI::GetParam<int>("seed") != 0)
    math::RandomSeed((size_t) CLI::GetParam<int>("seed"));
  else
    math::RandomSeed((size_t) std::time(NULL));

  const string inputFile = CLI::GetParam<string>("input_file");
  const string labelsFile = CLI::GetParam<string>("labels_file");
  const string outputFile = CLI::GetParam<string>("output_file");

  const double stepSize = CLI::GetParam<double>("step_size");
  const size_t maxIterations = (size_t) CLI::GetParam<int>("max_iterations");
  const double tolerance = CLI::GetParam<double>("tolerance");
  const bool normalize = CLI::HasParam("normalize");
  const bool shuffle = !CLI::HasParam("linear_scan");

  // Load data.
  mat data;
  data::Load(inputFile.c_str(), data, true);

  // Do we want to load labels separately?
  umat labels(data.n_cols, 1);
  if (labelsFile != "")
  {
    data::Load(labelsFile.c_str(), labels, true);

    if (labels.n_rows == 1)
      labels = trans(labels);

    if (labels.n_cols > 1)
      Log::Fatal << "Labels must have only one column or row!" << endl;
  }
  else
  {
    for (size_t i = 0; i < data.n_cols; i++)
      labels[i] = (int) data(data.n_rows - 1, i);

    data.shed_row(data.n_rows - 1);
  }

  mat distance;

  // Normalize the data, if necessary.
  if (normalize)
  {
    // Find the minimum and maximum values for each dimension.
    distance = diagmat(1.0 / (arma::max(data, 1) - arma::min(data, 1)));
    Log::Info << "Using normalized starting point for SGD." << std::endl;
  }
  else
  {
    distance.eye();
  }

  // Now create the NCA object and run the optimization.
  NCA<LMetric<2> > nca(data, labels.unsafe_col(0), stepSize, maxIterations,
      tolerance, shuffle);

  nca.LearnDistance(distance);

  Log::Warn << trans(distance);

  // Save the output.
  data::Save(CLI::GetParam<string>("output_file").c_str(), distance, true);
}
<commit_msg>No need to print the final matrix.<commit_after>/**
 * @file nca_main.cpp
 * @author Ryan Curtin
 *
 * Executable for Neighborhood Components Analysis.
 */
#include <mlpack/core.hpp>
#include <mlpack/core/metrics/lmetric.hpp>

#include "nca.hpp"

// Define parameters.
PROGRAM_INFO("Neighborhood Components Analysis (NCA)",
    "This program implements Neighborhood Components Analysis, both a linear "
    "dimensionality reduction technique and a distance learning technique.  The"
    " method seeks to improve k-nearest-neighbor classification on a dataset "
    "by scaling the dimensions.  The method is nonparametric, and does not "
    "require a value of k.  It works by using stochastic (\"soft\") neighbor "
    "assignments and using optimization techniques over the gradient of the "
    "accuracy of the neighbor assignments.\n"
    "\n"
    "To work, this algorithm needs labeled data.  It can be given as the last "
    "row of the input dataset (--input_file), or alternatively in a separate "
    "file (--labels_file).");

PARAM_STRING_REQ("input_file", "Input dataset to run NCA on.", "i");
PARAM_STRING_REQ("output_file", "Output file for learned distance matrix.",
    "o");
PARAM_STRING("labels_file", "File of labels for input dataset.", "l", "");
PARAM_DOUBLE("step_size", "Step size for stochastic gradient descent (alpha).",
    "a", 0.01);
PARAM_INT("max_iterations", "Maximum number of iterations for stochastic "
    "gradient descent (0 indicates no limit).", "n", 500000);
PARAM_DOUBLE("tolerance", "Maximum tolerance for termination of stochastic "
    "gradient descent.", "t", 1e-7);
PARAM_FLAG("normalize", "Use a normalized starting point for optimization. This"
    " is useful for when points are far apart, or when SGD is returning NaN.",
    "N");
PARAM_INT("seed", "Random seed.  If 0, 'std::time(NULL)' is used.", "s", 0);
PARAM_FLAG("linear_scan", "Don't shuffle the order in which data points are "
    "visited for SGD.", "L");

using namespace mlpack;
using namespace mlpack::nca;
using namespace mlpack::metric;
using namespace std;
using namespace arma;

int main(int argc, char* argv[])
{
  // Parse command line.
  CLI::ParseCommandLine(argc, argv);

  if (CLI::GetParam<int>("seed") != 0)
    math::RandomSeed((size_t) CLI::GetParam<int>("seed"));
  else
    math::RandomSeed((size_t) std::time(NULL));

  const string inputFile = CLI::GetParam<string>("input_file");
  const string labelsFile = CLI::GetParam<string>("labels_file");
  const string outputFile = CLI::GetParam<string>("output_file");

  const double stepSize = CLI::GetParam<double>("step_size");
  const size_t maxIterations = (size_t) CLI::GetParam<int>("max_iterations");
  const double tolerance = CLI::GetParam<double>("tolerance");
  const bool normalize = CLI::HasParam("normalize");
  const bool shuffle = !CLI::HasParam("linear_scan");

  // Load data.
  mat data;
  data::Load(inputFile.c_str(), data, true);

  // Do we want to load labels separately?
  umat labels(data.n_cols, 1);
  if (labelsFile != "")
  {
    data::Load(labelsFile.c_str(), labels, true);

    if (labels.n_rows == 1)
      labels = trans(labels);

    if (labels.n_cols > 1)
      Log::Fatal << "Labels must have only one column or row!" << endl;
  }
  else
  {
    for (size_t i = 0; i < data.n_cols; i++)
      labels[i] = (int) data(data.n_rows - 1, i);

    data.shed_row(data.n_rows - 1);
  }

  mat distance;

  // Normalize the data, if necessary.
  if (normalize)
  {
    // Find the minimum and maximum values for each dimension.
    distance = diagmat(1.0 / (arma::max(data, 1) - arma::min(data, 1)));
    Log::Info << "Using normalized starting point for SGD." << std::endl;
  }
  else
  {
    distance.eye();
  }

  // Now create the NCA object and run the optimization.
  NCA<LMetric<2> > nca(data, labels.unsafe_col(0), stepSize, maxIterations,
      tolerance, shuffle);

  nca.LearnDistance(distance);

  // Save the output.
  data::Save(CLI::GetParam<string>("output_file").c_str(), distance, true);
}
<|endoftext|>


<commit_before><commit_msg>added argument parsing to ls<commit_after><|endoftext|>


<commit_before><commit_msg>Time to add recusion<commit_after><|endoftext|>