<commit_before>#include "RigidBody.h"
#include "RbCollider.h"
#include "DistanceJoint.h"

#include "Application.h"
#include "Transform.h"
#include "jpPhysicsRigidBody.h"

RigidBody::RigidBody(GameObject * parent, bool isactive) : Component(parent, COMP_RIGIDBODY, true)
{
	joint_ptr = nullptr;
	if (parent != nullptr)
		parent->AddComponent(this);
}

RigidBody::~RigidBody()
{
	if (physics_body) {
		delete physics_body;
		physics_body = nullptr;
	}

	if (collider_comp != nullptr) {
		collider_comp->SetRigidBodyComp(nullptr);
		collider_comp->SetPhysicsBody(nullptr);
	}

	if (joint_ptr != nullptr)
	{
		joint_ptr->StopUsing(UUID);
	}

}

void RigidBody::Update()
{
	if (transform && physics_body && App->clock.delta_time > 0)
	{
		if (dynamic)
			physics_body->px_body->wakeUp();
		physx::PxVec3 pos;
		physx::PxQuat rot;
		physics_body->GetTransform(pos, rot);
		transform->SetTransform(float3(pos.x, pos.y, pos.z), Quat(rot.x, rot.y, rot.z, rot.w));
		own_update = true;
	}
	else own_update = false;
}

void RigidBody::UpdateTransform()
{
	if(physics_body && !own_update) {
		float3 fpos = transform->GetPosition();
		Quat quat = transform->GetRotQuat();
		physics_body->px_body->setGlobalPose(physx::PxTransform(physx::PxVec3(fpos.x, fpos.y, fpos.z),physx::PxQuat(quat.x,quat.y,quat.z,quat.w)));
	}
}

void RigidBody::ChangeParent(GameObject * new_parent)
{
	Component::ChangeParent(new_parent);

	collider_comp = LookForCollider();

	if (collider_comp != nullptr)
	{
		collider_comp->SetRigidBodyComp(this);
		if (physics_body)
			delete physics_body;
		physics_body = collider_comp->GetPhysicsBody();
	}
	else {
		physics_body = App->physics->GetNewRigidBody(0);
	}
	//Make sure is dynamic
	physics_body->SetDynamic(dynamic);

	transform = new_parent->GetTransform();
	UpdateTransform();
}

void RigidBody::DrawComponent()
{
	ImGui::PushID(UUID);
	Component::DrawComponent();
	if (ImGui::CollapsingHeader("RigidBody"))
	{
		if (ImGui::Checkbox("Dynamic", &dynamic)) physics_body->SetDynamic(dynamic);
		if (ImGui::InputFloat("Mass", (float*)&mass, 0.1f, 1.f, 2, ImGuiInputTextFlags_EnterReturnsTrue))
			SetPhysicsBodyMass();
	}
	ImGui::PopID();
}

void RigidBody::SetPhysicsBody(jpPhysicsRigidBody * new_physics_body)
{
	// careful somethings wrong here
	physics_body = new_physics_body;
}

void RigidBody::SetPhysicsBodyMass()
{
	if (physics_body)
		physics_body->SetMass(mass);
}

void RigidBody::SetColliderComp(RbCollider * new_collider)
{
	collider_comp = new_collider;

	if (new_collider){
		jpPhysicsRigidBody* body = new_collider->GetPhysicsBody();
		if (body && physics_body != body) {
			if (physics_body)
				delete physics_body;
			physics_body = body;
			physics_body->SetDynamic(dynamic);
		}
	}
}

jpPhysicsRigidBody * RigidBody::GetPhysicsBody()
{
	return physics_body;
}

void RigidBody::Save(const char * buffer_data, char * cursor, int & bytes_copied)
{

	//identifier and type
	int identifier = COMPONENTIDENTIFIER;
	uint bytes_to_copy = sizeof(identifier);
	memcpy(cursor, &identifier, bytes_to_copy);
	cursor += bytes_to_copy;
	bytes_copied += bytes_to_copy;
	bytes_to_copy = sizeof(type);
	memcpy(cursor, &type, bytes_to_copy);
	cursor += bytes_to_copy;
	bytes_copied += bytes_to_copy;

	//UUID and parent UUID
	bytes_to_copy = sizeof(UUID);
	memcpy(cursor, &UUID, bytes_to_copy);
	cursor += bytes_to_copy;
	bytes_copied += bytes_to_copy;
	bytes_to_copy = sizeof(parent_UUID);
	memcpy(cursor, &parent_UUID, bytes_to_copy);
	cursor += bytes_to_copy;
	bytes_copied += bytes_to_copy;

	//active and unique
	bytes_to_copy = sizeof(bool);
	memcpy(cursor, &active, bytes_to_copy);
	cursor += bytes_to_copy;
	bytes_copied += bytes_to_copy;
	memcpy(cursor, &unique, bytes_to_copy);
	cursor += bytes_to_copy;
	bytes_copied += bytes_to_copy;

	///RigidBody comp
	bytes_to_copy = sizeof(bool);
	memcpy(cursor, &dynamic, bytes_to_copy);
	cursor += bytes_to_copy;
	bytes_copied += bytes_to_copy;
	memcpy(cursor, &own_update, bytes_to_copy);
	cursor += bytes_to_copy;
	bytes_copied += bytes_to_copy;
}

void RigidBody::Load(char * cursor, int & bytes_copied)
{
	//UUID and parentUUID
	uint bytes_to_copy = sizeof(int);
	memcpy(&UUID, cursor, bytes_to_copy);
	cursor += bytes_to_copy;
	bytes_copied += bytes_to_copy;
	memcpy(&parent_UUID, cursor, bytes_to_copy);
	cursor += bytes_to_copy;
	bytes_copied += bytes_to_copy;

	//active and unique
	bytes_to_copy = sizeof(bool);
	memcpy(&active, cursor, bytes_to_copy);
	cursor += bytes_to_copy;
	bytes_copied += bytes_to_copy;
	memcpy(&unique, cursor, bytes_to_copy);
	cursor += bytes_to_copy;
	bytes_copied += bytes_to_copy;

	///RigidBody comp
	bytes_to_copy = sizeof(bool);
	memcpy(&dynamic, cursor, bytes_to_copy);
	cursor += bytes_to_copy;
	bytes_copied += bytes_to_copy;
	memcpy(&own_update, cursor, bytes_to_copy);
	cursor += bytes_to_copy;
	bytes_copied += bytes_to_copy;
}

void RigidBody::GetOwnBufferSize(uint & buffer_size)
{
	Component::GetOwnBufferSize(buffer_size);
	buffer_size += sizeof(bool) * 2;
}

RbCollider * RigidBody::LookForCollider()
{
	if (parent != nullptr)
	{
		for (uint i = 0; i < parent->components.size(); i++)
		{
			if (parent->components[i]->GetType() == COMP_TYPE::COMP_RBSHAPE)
			{
				return (RbCollider*)parent->components[i];
			}
		}
	}
	return nullptr;
}
<commit_msg>mass save and load<commit_after>#include "RigidBody.h"
#include "RbCollider.h"
#include "DistanceJoint.h"

#include "Application.h"
#include "Transform.h"
#include "jpPhysicsRigidBody.h"

RigidBody::RigidBody(GameObject * parent, bool isactive) : Component(parent, COMP_RIGIDBODY, true)
{
	joint_ptr = nullptr;
	if (parent != nullptr)
		parent->AddComponent(this);
}

RigidBody::~RigidBody()
{
	if (physics_body) {
		delete physics_body;
		physics_body = nullptr;
	}

	if (collider_comp != nullptr) {
		collider_comp->SetRigidBodyComp(nullptr);
		collider_comp->SetPhysicsBody(nullptr);
	}

	if (joint_ptr != nullptr)
	{
		joint_ptr->StopUsing(UUID);
	}

}

void RigidBody::Update()
{
	if (transform && physics_body && App->clock.delta_time > 0)
	{
		if (dynamic)
			physics_body->px_body->wakeUp();
		physx::PxVec3 pos;
		physx::PxQuat rot;
		physics_body->GetTransform(pos, rot);
		transform->SetTransform(float3(pos.x, pos.y, pos.z), Quat(rot.x, rot.y, rot.z, rot.w));
		own_update = true;
	}
	else own_update = false;
}

void RigidBody::UpdateTransform()
{
	if(physics_body && !own_update) {
		float3 fpos = transform->GetPosition();
		Quat quat = transform->GetRotQuat();
		physics_body->px_body->setGlobalPose(physx::PxTransform(physx::PxVec3(fpos.x, fpos.y, fpos.z),physx::PxQuat(quat.x,quat.y,quat.z,quat.w)));
	}
}

void RigidBody::ChangeParent(GameObject * new_parent)
{
	Component::ChangeParent(new_parent);

	collider_comp = LookForCollider();

	if (collider_comp != nullptr)
	{
		collider_comp->SetRigidBodyComp(this);
		if (physics_body)
			delete physics_body;
		physics_body = collider_comp->GetPhysicsBody();
	}
	else {
		physics_body = App->physics->GetNewRigidBody(0);
	}
	//Make sure is dynamic
	physics_body->SetDynamic(dynamic);

	transform = new_parent->GetTransform();
	UpdateTransform();
}

void RigidBody::DrawComponent()
{
	ImGui::PushID(UUID);
	Component::DrawComponent();
	if (ImGui::CollapsingHeader("RigidBody"))
	{
		if (ImGui::Checkbox("Dynamic", &dynamic)) physics_body->SetDynamic(dynamic);
		if (ImGui::InputFloat("Mass", (float*)&mass, 0.1f, 1.f, 2, ImGuiInputTextFlags_EnterReturnsTrue))
			SetPhysicsBodyMass();
	}
	ImGui::PopID();
}

void RigidBody::SetPhysicsBody(jpPhysicsRigidBody * new_physics_body)
{
	// careful somethings wrong here
	physics_body = new_physics_body;
}

void RigidBody::SetPhysicsBodyMass()
{
	if (physics_body)
		physics_body->SetMass(mass);
}

void RigidBody::SetColliderComp(RbCollider * new_collider)
{
	collider_comp = new_collider;

	if (new_collider){
		jpPhysicsRigidBody* body = new_collider->GetPhysicsBody();
		if (body && physics_body != body) {
			if (physics_body)
				delete physics_body;
			physics_body = body;
			physics_body->SetDynamic(dynamic);
		}
	}
}

jpPhysicsRigidBody * RigidBody::GetPhysicsBody()
{
	return physics_body;
}

void RigidBody::Save(const char * buffer_data, char * cursor, int & bytes_copied)
{

	//identifier and type
	int identifier = COMPONENTIDENTIFIER;
	uint bytes_to_copy = sizeof(identifier);
	memcpy(cursor, &identifier, bytes_to_copy);
	cursor += bytes_to_copy;
	bytes_copied += bytes_to_copy;
	bytes_to_copy = sizeof(type);
	memcpy(cursor, &type, bytes_to_copy);
	cursor += bytes_to_copy;
	bytes_copied += bytes_to_copy;

	//UUID and parent UUID
	bytes_to_copy = sizeof(UUID);
	memcpy(cursor, &UUID, bytes_to_copy);
	cursor += bytes_to_copy;
	bytes_copied += bytes_to_copy;
	bytes_to_copy = sizeof(parent_UUID);
	memcpy(cursor, &parent_UUID, bytes_to_copy);
	cursor += bytes_to_copy;
	bytes_copied += bytes_to_copy;

	//active and unique
	bytes_to_copy = sizeof(bool);
	memcpy(cursor, &active, bytes_to_copy);
	cursor += bytes_to_copy;
	bytes_copied += bytes_to_copy;
	memcpy(cursor, &unique, bytes_to_copy);
	cursor += bytes_to_copy;
	bytes_copied += bytes_to_copy;

	///RigidBody comp
	bytes_to_copy = sizeof(bool);
	memcpy(cursor, &dynamic, bytes_to_copy);
	cursor += bytes_to_copy;
	bytes_copied += bytes_to_copy;
	memcpy(cursor, &own_update, bytes_to_copy);
	cursor += bytes_to_copy;
	bytes_copied += bytes_to_copy;

	bytes_to_copy = sizeof(float);
	memcpy(cursor, &mass, bytes_to_copy);
	cursor += bytes_to_copy;
	bytes_copied += bytes_to_copy;
}

void RigidBody::Load(char * cursor, int & bytes_copied)
{
	//UUID and parentUUID
	uint bytes_to_copy = sizeof(int);
	memcpy(&UUID, cursor, bytes_to_copy);
	cursor += bytes_to_copy;
	bytes_copied += bytes_to_copy;
	memcpy(&parent_UUID, cursor, bytes_to_copy);
	cursor += bytes_to_copy;
	bytes_copied += bytes_to_copy;

	//active and unique
	bytes_to_copy = sizeof(bool);
	memcpy(&active, cursor, bytes_to_copy);
	cursor += bytes_to_copy;
	bytes_copied += bytes_to_copy;
	memcpy(&unique, cursor, bytes_to_copy);
	cursor += bytes_to_copy;
	bytes_copied += bytes_to_copy;

	///RigidBody comp
	bytes_to_copy = sizeof(bool);
	memcpy(&dynamic, cursor, bytes_to_copy);
	cursor += bytes_to_copy;
	bytes_copied += bytes_to_copy;
	memcpy(&own_update, cursor, bytes_to_copy);
	cursor += bytes_to_copy;
	bytes_copied += bytes_to_copy;

	bytes_to_copy = sizeof(float);
	memcpy(&mass, cursor, bytes_to_copy);
	cursor += bytes_to_copy;
	bytes_copied += bytes_to_copy;
}

void RigidBody::GetOwnBufferSize(uint & buffer_size)
{
	Component::GetOwnBufferSize(buffer_size);
	buffer_size += sizeof(bool) * 2;
	buffer_size += sizeof(float);
}

RbCollider * RigidBody::LookForCollider()
{
	if (parent != nullptr)
	{
		for (uint i = 0; i < parent->components.size(); i++)
		{
			if (parent->components[i]->GetType() == COMP_TYPE::COMP_RBSHAPE)
			{
				return (RbCollider*)parent->components[i];
			}
		}
	}
	return nullptr;
}
<|endoftext|>


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

 This file is part of the GLC-lib library.
 Copyright (C) 2005-2008 Laurent Ribon (laumaya@users.sourceforge.net)
 Version 1.2.0, packaged on September 2009.

 http://glc-lib.sourceforge.net

 GLC-lib 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 2 of the License, or
 (at your option) any later version.

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

 You should have received a copy of the GNU General Public License
 along with GLC-lib; if not, write to the Free Software
 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA

 *****************************************************************************/
//! \file glc_cuttingplane.cpp Implementation of the GLC_CuttingPlane class.

#include "glc_cuttingplane.h"
#include "../glc_factory.h"
#include "../maths/glc_line3d.h"
#include "../maths/glc_geomtools.h"
#include "../geometry/glc_arrow.h"
#include "../geometry/glc_disc.h"

GLC_CuttingPlane::GLC_CuttingPlane(const GLC_Point3d& center, const GLC_Vector3d& normal, double l1, double l2, GLC_3DWidgetManagerHandle*  pWidgetManagerHandle)
: GLC_3DWidget(pWidgetManagerHandle)
, m_Center(center)
, m_Normal(normal)
, m_L1(l1)
, m_L2(l2)
, m_Previous()
, m_SlidingPlane()
, m_Color(Qt::darkGreen)
, m_Opacity(0.3)
{
	if (NULL != pWidgetManagerHandle)
	{
		create3DviewInstance();
	}
}

GLC_CuttingPlane::GLC_CuttingPlane(const GLC_CuttingPlane& cuttingPlane)
: GLC_3DWidget(cuttingPlane)
, m_Center(cuttingPlane.m_Center)
, m_Normal(cuttingPlane.m_Normal)
, m_L1(cuttingPlane.m_L1)
, m_L2(cuttingPlane.m_L2)
, m_Previous()
, m_SlidingPlane()
, m_Color(cuttingPlane.m_Color)
, m_Opacity(cuttingPlane.m_Opacity)
{

}

GLC_CuttingPlane::~GLC_CuttingPlane()
{

}

GLC_CuttingPlane& GLC_CuttingPlane::operator=(const GLC_CuttingPlane& cuttingPlane)
{
	GLC_3DWidget::operator=(cuttingPlane);

	m_Center= cuttingPlane.m_Center;
	m_Normal= cuttingPlane.m_Normal;
	m_L1= cuttingPlane.m_L1;
	m_L2= cuttingPlane.m_L2;
	m_Color= cuttingPlane.m_Color;
	m_Opacity= cuttingPlane.m_Opacity;

	return *this;
}

void GLC_CuttingPlane::updateLength(double l1, double l2)
{
	m_L1= l1;
	m_L2= l2;

	if (GLC_3DWidget::has3DWidgetManager())
	{
		GLC_3DWidget::remove3DViewInstance();
		create3DviewInstance();
	}
}

void GLC_CuttingPlane::viewportAsChanged()
{
	const double viewTangent= GLC_3DWidget::widgetManagerHandle()->viewportTangent();
	const GLC_Point3d eye(GLC_3DWidget::widgetManagerHandle()->cameraHandle()->eye());
	const double distanceToNormal= (m_Previous - eye).length();
	const double viewWidth= distanceToNormal * viewTangent;
	updateArrow(viewWidth * 0.1);
}

glc::WidgetEventFlag GLC_CuttingPlane::select(const GLC_Point3d& pos)
{
	// Update previous point
	m_Previous= pos;
	prepareToSlide();

	GLC_3DWidget::set3DViewInstanceVisibility(1, true);
	GLC_3DWidget::set3DViewInstanceVisibility(2, true);

	GLC_Matrix4x4 translationMatrix(pos);
	GLC_3DWidget::instanceHandle(1)->setMatrix(translationMatrix);
	GLC_3DWidget::instanceHandle(2)->setMatrix(translationMatrix);

	return glc::BlockedEvent;
}

glc::WidgetEventFlag GLC_CuttingPlane::mousePressed(const GLC_Point3d& pos, Qt::MouseButton button)
{
	glc::WidgetEventFlag returnFlag= glc::IgnoreEvent;
	if (button == Qt::LeftButton)
	{
		m_Previous= pos;
		prepareToSlide();
		returnFlag= glc::BlockedEvent;

		GLC_3DWidget::set3DViewInstanceVisibility(1, true);
		GLC_3DWidget::set3DViewInstanceVisibility(2, true);

		GLC_Matrix4x4 translationMatrix(pos);
		GLC_3DWidget::instanceHandle(1)->setMatrix(translationMatrix);
		GLC_3DWidget::instanceHandle(2)->setMatrix(translationMatrix);
	}

	return returnFlag;
}

glc::WidgetEventFlag GLC_CuttingPlane::unselect(const GLC_Point3d&)
{
	GLC_3DWidget::set3DViewInstanceVisibility(1, false);
	GLC_3DWidget::set3DViewInstanceVisibility(2, false);

	return glc::AcceptEvent;
}

glc::WidgetEventFlag GLC_CuttingPlane::mouseOver(const GLC_Point3d&)
{
	return glc::AcceptEvent;
}

glc::WidgetEventFlag GLC_CuttingPlane::mouseMove(const GLC_Point3d& pos, Qt::MouseButtons)
{
	// Projection of intersection point on slidding plane
	const GLC_Point3d eye(GLC_3DWidget::widgetManagerHandle()->cameraHandle()->eye());
	GLC_Vector3d direction;
	if (GLC_3DWidget::useOrtho())
	{
		direction= GLC_3DWidget::widgetManagerHandle()->cameraHandle()->forward().normalize();
	}
	else
	{
		direction= (pos - eye);
	}

	GLC_Point3d sliddingPoint;
	GLC_Line3d projectionLine(pos, direction);
	glc::lineIntersectPlane(projectionLine, m_SlidingPlane, &sliddingPoint);

	GLC_Vector3d projNormal= (GLC_3DWidget::widgetManagerHandle()->cameraHandle()->sideVector() ^ m_Normal).normalize();
	GLC_Plane projPlane(projNormal, m_Previous);
	glc::lineIntersectPlane(projectionLine, projPlane, &sliddingPoint);

	// Projection of the slidding point on cutting plane normal
	sliddingPoint= glc::project(sliddingPoint, GLC_Line3d(m_Previous, m_Normal));

	GLC_Matrix4x4 translationMatrix(sliddingPoint - m_Previous);

	// Update the instance
	GLC_3DWidget::instanceHandle(0)->multMatrix(translationMatrix);
	GLC_3DWidget::instanceHandle(1)->multMatrix(translationMatrix);
	GLC_3DWidget::instanceHandle(2)->multMatrix(translationMatrix);

	// Update plane center
	m_Center= translationMatrix * m_Center;

	m_Previous= sliddingPoint;

	// Plane throw intersection and plane normal and camera up vector
	GLC_Plane sliddingPlane(GLC_3DWidget::widgetManagerHandle()->cameraHandle()->forward().normalize(), m_Previous);
	m_SlidingPlane= sliddingPlane;

	emit asChanged();

	return glc::AcceptEvent;
}

void GLC_CuttingPlane::create3DviewInstance()
{
	Q_ASSERT(GLC_3DWidget::isEmpty());
	// The cutting plane material
	GLC_Material* pMaterial= new GLC_Material(m_Color);
	pMaterial->setOpacity(m_Opacity);

	// Cutting plane 3Dview instance
	GLC_3DViewInstance cuttingPlaneInstance= GLC_Factory::instance()->createCuttingPlane(m_Center, m_Normal, m_L1, m_L2, pMaterial);
	GLC_3DWidget::add3DViewInstance(cuttingPlaneInstance);

	// Normal arrow geometry
	GLC_Arrow* pArrow= new GLC_Arrow(GLC_Point3d(), -m_Normal, GLC_3DWidget::widgetManagerHandle()->cameraHandle()->forward().normalize());
	pArrow->setLineWidth(2.5);
	QColor arrowColor(Qt::red);
	arrowColor.setAlphaF(0.4);
	pArrow->setWireColor(arrowColor);

	//Base arrow disc
	pMaterial= new GLC_Material(Qt::red);
	pMaterial->setOpacity(m_Opacity);
	GLC_Disc* pDisc= new GLC_Disc(1.0);
	pDisc->replaceMasterMaterial(pMaterial);

	// Normal arrow + base instance
	GLC_3DViewInstance normalLine(pArrow);
	GLC_3DWidget::add3DViewInstance(normalLine);
	GLC_3DWidget::set3DViewInstanceVisibility(1, false);

	GLC_3DViewInstance normalBase(pDisc);
	GLC_3DWidget::add3DViewInstance(normalBase);
	GLC_3DWidget::set3DViewInstanceVisibility(2, false);

}

void GLC_CuttingPlane::prepareToSlide()
{
	// Plane throw intersection and plane normal and camera up vector
	GLC_Plane sliddingPlane(GLC_3DWidget::widgetManagerHandle()->cameraHandle()->forward().normalize(), m_Previous);
	m_SlidingPlane= sliddingPlane;

	// Projection of intersection point on slidding plane
	const GLC_Point3d eye(GLC_3DWidget::widgetManagerHandle()->cameraHandle()->eye());
	const GLC_Vector3d direction((m_Previous - eye).normalize());

	GLC_Line3d projectionLine(m_Previous, direction);
	glc::lineIntersectPlane(projectionLine, m_SlidingPlane, &m_Previous);

	//m_Previous= glc::project(m_Previous, GLC_Line3d(m_Previous, m_Normal));
}

void GLC_CuttingPlane::updateArrow(double length)
{
	GLC_Arrow* pArrow= dynamic_cast<GLC_Arrow*>(GLC_3DWidget::instanceHandle(1)->geomAt(0));
	Q_ASSERT(NULL != pArrow);

	pArrow->setEndPoint(-m_Normal * length);
	pArrow->setHeadLength(length * 0.15);
	pArrow->setViewDir(GLC_3DWidget::widgetManagerHandle()->cameraHandle()->forward().normalize());

	GLC_Disc* pDisc= dynamic_cast<GLC_Disc*>(GLC_3DWidget::instanceHandle(2)->geomAt(0));
	Q_ASSERT(NULL != pDisc);
	pDisc->setRadius(pArrow->headLenght());
}
<commit_msg>Minor Change : Change arrow size.<commit_after>/****************************************************************************

 This file is part of the GLC-lib library.
 Copyright (C) 2005-2008 Laurent Ribon (laumaya@users.sourceforge.net)
 Version 1.2.0, packaged on September 2009.

 http://glc-lib.sourceforge.net

 GLC-lib 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 2 of the License, or
 (at your option) any later version.

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

 You should have received a copy of the GNU General Public License
 along with GLC-lib; if not, write to the Free Software
 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA

 *****************************************************************************/
//! \file glc_cuttingplane.cpp Implementation of the GLC_CuttingPlane class.

#include "glc_cuttingplane.h"
#include "../glc_factory.h"
#include "../maths/glc_line3d.h"
#include "../maths/glc_geomtools.h"
#include "../geometry/glc_arrow.h"
#include "../geometry/glc_disc.h"

GLC_CuttingPlane::GLC_CuttingPlane(const GLC_Point3d& center, const GLC_Vector3d& normal, double l1, double l2, GLC_3DWidgetManagerHandle*  pWidgetManagerHandle)
: GLC_3DWidget(pWidgetManagerHandle)
, m_Center(center)
, m_Normal(normal)
, m_L1(l1)
, m_L2(l2)
, m_Previous()
, m_SlidingPlane()
, m_Color(Qt::darkGreen)
, m_Opacity(0.3)
{
	if (NULL != pWidgetManagerHandle)
	{
		create3DviewInstance();
	}
}

GLC_CuttingPlane::GLC_CuttingPlane(const GLC_CuttingPlane& cuttingPlane)
: GLC_3DWidget(cuttingPlane)
, m_Center(cuttingPlane.m_Center)
, m_Normal(cuttingPlane.m_Normal)
, m_L1(cuttingPlane.m_L1)
, m_L2(cuttingPlane.m_L2)
, m_Previous()
, m_SlidingPlane()
, m_Color(cuttingPlane.m_Color)
, m_Opacity(cuttingPlane.m_Opacity)
{

}

GLC_CuttingPlane::~GLC_CuttingPlane()
{

}

GLC_CuttingPlane& GLC_CuttingPlane::operator=(const GLC_CuttingPlane& cuttingPlane)
{
	GLC_3DWidget::operator=(cuttingPlane);

	m_Center= cuttingPlane.m_Center;
	m_Normal= cuttingPlane.m_Normal;
	m_L1= cuttingPlane.m_L1;
	m_L2= cuttingPlane.m_L2;
	m_Color= cuttingPlane.m_Color;
	m_Opacity= cuttingPlane.m_Opacity;

	return *this;
}

void GLC_CuttingPlane::updateLength(double l1, double l2)
{
	m_L1= l1;
	m_L2= l2;

	if (GLC_3DWidget::has3DWidgetManager())
	{
		GLC_3DWidget::remove3DViewInstance();
		create3DviewInstance();
	}
}

void GLC_CuttingPlane::viewportAsChanged()
{
	const double viewTangent= GLC_3DWidget::widgetManagerHandle()->viewportTangent();
	const GLC_Point3d eye(GLC_3DWidget::widgetManagerHandle()->cameraHandle()->eye());
	const double distanceToNormal= (m_Previous - eye).length();
	const double viewWidth= distanceToNormal * viewTangent;
	updateArrow(viewWidth * 0.06);
}

glc::WidgetEventFlag GLC_CuttingPlane::select(const GLC_Point3d& pos)
{
	// Update previous point
	m_Previous= pos;
	prepareToSlide();

	GLC_3DWidget::set3DViewInstanceVisibility(1, true);
	GLC_3DWidget::set3DViewInstanceVisibility(2, true);

	GLC_Matrix4x4 translationMatrix(pos);
	GLC_3DWidget::instanceHandle(1)->setMatrix(translationMatrix);
	GLC_3DWidget::instanceHandle(2)->setMatrix(translationMatrix);

	return glc::BlockedEvent;
}

glc::WidgetEventFlag GLC_CuttingPlane::mousePressed(const GLC_Point3d& pos, Qt::MouseButton button)
{
	glc::WidgetEventFlag returnFlag= glc::IgnoreEvent;
	if (button == Qt::LeftButton)
	{
		m_Previous= pos;
		prepareToSlide();
		returnFlag= glc::BlockedEvent;

		GLC_3DWidget::set3DViewInstanceVisibility(1, true);
		GLC_3DWidget::set3DViewInstanceVisibility(2, true);

		GLC_Matrix4x4 translationMatrix(pos);
		GLC_3DWidget::instanceHandle(1)->setMatrix(translationMatrix);
		GLC_3DWidget::instanceHandle(2)->setMatrix(translationMatrix);
	}

	return returnFlag;
}

glc::WidgetEventFlag GLC_CuttingPlane::unselect(const GLC_Point3d&)
{
	GLC_3DWidget::set3DViewInstanceVisibility(1, false);
	GLC_3DWidget::set3DViewInstanceVisibility(2, false);

	return glc::AcceptEvent;
}

glc::WidgetEventFlag GLC_CuttingPlane::mouseOver(const GLC_Point3d&)
{
	return glc::AcceptEvent;
}

glc::WidgetEventFlag GLC_CuttingPlane::mouseMove(const GLC_Point3d& pos, Qt::MouseButtons)
{
	// Projection of intersection point on slidding plane
	const GLC_Point3d eye(GLC_3DWidget::widgetManagerHandle()->cameraHandle()->eye());
	GLC_Vector3d direction;
	if (GLC_3DWidget::useOrtho())
	{
		direction= GLC_3DWidget::widgetManagerHandle()->cameraHandle()->forward().normalize();
	}
	else
	{
		direction= (pos - eye);
	}

	GLC_Point3d sliddingPoint;
	GLC_Line3d projectionLine(pos, direction);
	glc::lineIntersectPlane(projectionLine, m_SlidingPlane, &sliddingPoint);

	GLC_Vector3d projNormal= (GLC_3DWidget::widgetManagerHandle()->cameraHandle()->sideVector() ^ m_Normal).normalize();
	GLC_Plane projPlane(projNormal, m_Previous);
	glc::lineIntersectPlane(projectionLine, projPlane, &sliddingPoint);

	// Projection of the slidding point on cutting plane normal
	sliddingPoint= glc::project(sliddingPoint, GLC_Line3d(m_Previous, m_Normal));

	GLC_Matrix4x4 translationMatrix(sliddingPoint - m_Previous);

	// Update the instance
	GLC_3DWidget::instanceHandle(0)->multMatrix(translationMatrix);
	GLC_3DWidget::instanceHandle(1)->multMatrix(translationMatrix);
	GLC_3DWidget::instanceHandle(2)->multMatrix(translationMatrix);

	// Update plane center
	m_Center= translationMatrix * m_Center;

	m_Previous= sliddingPoint;

	// Plane throw intersection and plane normal and camera up vector
	GLC_Plane sliddingPlane(GLC_3DWidget::widgetManagerHandle()->cameraHandle()->forward().normalize(), m_Previous);
	m_SlidingPlane= sliddingPlane;

	emit asChanged();

	return glc::AcceptEvent;
}

void GLC_CuttingPlane::create3DviewInstance()
{
	Q_ASSERT(GLC_3DWidget::isEmpty());
	// The cutting plane material
	GLC_Material* pMaterial= new GLC_Material(m_Color);
	pMaterial->setOpacity(m_Opacity);

	// Cutting plane 3Dview instance
	GLC_3DViewInstance cuttingPlaneInstance= GLC_Factory::instance()->createCuttingPlane(m_Center, m_Normal, m_L1, m_L2, pMaterial);
	GLC_3DWidget::add3DViewInstance(cuttingPlaneInstance);

	// Normal arrow geometry
	GLC_Arrow* pArrow= new GLC_Arrow(GLC_Point3d(), -m_Normal, GLC_3DWidget::widgetManagerHandle()->cameraHandle()->forward().normalize());
	pArrow->setLineWidth(2.5);
	QColor arrowColor(Qt::red);
	arrowColor.setAlphaF(0.4);
	pArrow->setWireColor(arrowColor);

	if (pArrow->isTransparent())
	{
		qDebug() << "Arrow is transparent";
	}
	else
	{
		qDebug() << "Arrow is NOT transparent";
	}
	//Base arrow disc
	pMaterial= new GLC_Material(Qt::red);
	pMaterial->setOpacity(m_Opacity);
	GLC_Disc* pDisc= new GLC_Disc(1.0);
	pDisc->replaceMasterMaterial(pMaterial);

	// Normal arrow + base instance
	GLC_3DViewInstance normalLine(pArrow);
	GLC_3DWidget::add3DViewInstance(normalLine);
	GLC_3DWidget::set3DViewInstanceVisibility(1, false);

	GLC_3DViewInstance normalBase(pDisc);
	GLC_3DWidget::add3DViewInstance(normalBase);
	GLC_3DWidget::set3DViewInstanceVisibility(2, false);

}

void GLC_CuttingPlane::prepareToSlide()
{
	// Plane throw intersection and plane normal and camera up vector
	GLC_Plane sliddingPlane(GLC_3DWidget::widgetManagerHandle()->cameraHandle()->forward().normalize(), m_Previous);
	m_SlidingPlane= sliddingPlane;

	// Projection of intersection point on slidding plane
	const GLC_Point3d eye(GLC_3DWidget::widgetManagerHandle()->cameraHandle()->eye());
	const GLC_Vector3d direction((m_Previous - eye).normalize());

	GLC_Line3d projectionLine(m_Previous, direction);
	glc::lineIntersectPlane(projectionLine, m_SlidingPlane, &m_Previous);

	//m_Previous= glc::project(m_Previous, GLC_Line3d(m_Previous, m_Normal));
}

void GLC_CuttingPlane::updateArrow(double length)
{
	GLC_Arrow* pArrow= dynamic_cast<GLC_Arrow*>(GLC_3DWidget::instanceHandle(1)->geomAt(0));
	Q_ASSERT(NULL != pArrow);

	pArrow->setEndPoint(-m_Normal * length);
	pArrow->setHeadLength(length * 0.15);
	pArrow->setViewDir(GLC_3DWidget::widgetManagerHandle()->cameraHandle()->forward().normalize());

	GLC_Disc* pDisc= dynamic_cast<GLC_Disc*>(GLC_3DWidget::instanceHandle(2)->geomAt(0));
	Q_ASSERT(NULL != pDisc);
	pDisc->setRadius(length * 0.3);
}
<|endoftext|>


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

#include "scanner/video/decoder_automata.h"
#include "scanner/metadata.pb.h"

#include "scanner/util/h264.h"
#include "scanner/util/memory.h"

#include <thread>

namespace scanner {
namespace internal {

DecoderAutomata::DecoderAutomata(DeviceHandle device_handle, i32 num_devices,
                                 VideoDecoderType decoder_type)
  : device_handle_(device_handle),
    num_devices_(num_devices),
    decoder_type_(decoder_type),
    decoder_(
      VideoDecoder::make_from_config(device_handle, num_devices, decoder_type)),
    feeder_waiting_(false),
    not_done_(true),
    frames_retrieved_(0),
    skip_frames_(false) {
  feeder_thread_ = std::thread(&DecoderAutomata::feeder, this);
}

DecoderAutomata::~DecoderAutomata() {
  {
    frames_to_get_ = 0;
    frames_retrieved_ = 0;
    while (decoder_->discard_frame()) {
    }

    std::unique_lock<std::mutex> lk(feeder_mutex_);
    wake_feeder_.wait(lk, [this] { return feeder_waiting_.load(); });

    if (frames_retrieved_ > 0) {
      decoder_->feed(nullptr, 0, true);
    }
    not_done_ = false;
    feeder_waiting_ = false;
  }
  wake_feeder_.notify_one();
  feeder_thread_.join();
}

void DecoderAutomata::initialize(
  const std::vector<proto::DecodeArgs>& encoded_data) {
  assert(!encoded_data.empty());
  encoded_data_ = encoded_data;
  frame_size_ = encoded_data[0].width() * encoded_data[0].height() * 3;
  current_frame_ = encoded_data[0].start_keyframe();
  next_frame_.store(encoded_data[0].valid_frames(0), std::memory_order_release);
  retriever_data_idx_.store(0, std::memory_order_release);
  retriever_valid_idx_ = 0;

  FrameInfo info;
  info.set_width(encoded_data[0].width());
  info.set_height(encoded_data[0].height());

  while (decoder_->discard_frame()) {
  }

  std::unique_lock<std::mutex> lk(feeder_mutex_);
  wake_feeder_.wait(lk, [this] { return feeder_waiting_.load(); });

  if (info_.width() != info.width() || info_.height() != info.height()) {
    decoder_->configure(info);
  }
  if (frames_retrieved_ > 0) {
    decoder_->feed(nullptr, 0, true);
  }

  set_feeder_idx(0);
  info_ = info;
  std::atomic_thread_fence(std::memory_order_release);
  seeking_ = false;
}

void DecoderAutomata::get_frames(u8* buffer, i32 num_frames) {
  i64 total_frames_decoded = 0;
  i64 total_frames_used = 0;

  auto start = now();

  // Wait until feeder is waiting
  {
    // Wait until frames are being requested
    std::unique_lock<std::mutex> lk(feeder_mutex_);
    wake_feeder_.wait(lk, [this] { return feeder_waiting_.load(); });
  }

  // Start up feeder thread
  {
    std::unique_lock<std::mutex> lk(feeder_mutex_);
    frames_retrieved_ = 0;
    frames_to_get_ = num_frames;
    feeder_waiting_ = false;
  }
  wake_feeder_.notify_one();

  if (profiler_) {
    profiler_->add_interval("get_frames_wait", start, now());
  }

  while (frames_retrieved_ < frames_to_get_) {
    if (decoder_->decoded_frames_buffered() > 0) {
      auto iter = now();
      // New frames
      bool more_frames = true;
      while (more_frames && frames_retrieved_ < frames_to_get_) {
        const auto& valid_frames =
          encoded_data_[retriever_data_idx_].valid_frames();
        assert(valid_frames.size() > retriever_valid_idx_.load());
        assert(current_frame_ <= valid_frames.Get(retriever_valid_idx_));
        // printf("has buffered frames, curr %d, next %d\n",
        //        current_frame_, valid_frames.Get(retriever_valid_idx_));
        if (current_frame_ == valid_frames.Get(retriever_valid_idx_)) {
          u8* decoded_buffer = buffer + frames_retrieved_ * frame_size_;
          more_frames = decoder_->get_frame(decoded_buffer, frame_size_);
          retriever_valid_idx_++;
          if (retriever_valid_idx_ == valid_frames.size()) {
            // Move to next decode args
            retriever_data_idx_ += 1;
            retriever_valid_idx_ = 0;

            // Trigger feeder to start again and set ourselves to the
            // start of that keyframe
            if (retriever_data_idx_ < encoded_data_.size()) {
              {
                // Wait until feeder is waiting
                // skip_frames_ = true;
                std::unique_lock<std::mutex> lk(feeder_mutex_);
                wake_feeder_.wait(lk, [this, &total_frames_decoded] {
                  while (decoder_->discard_frame()) {
                    total_frames_decoded++;
                  }
                  return feeder_waiting_.load();
                });
                // skip_frames_ = false;
              }

              {
                std::unique_lock<std::mutex> lk(feeder_mutex_);
                feeder_waiting_ = false;
                current_frame_ =
                  encoded_data_[retriever_data_idx_].keyframes(0) - 1;
              }
              wake_feeder_.notify_one();
            } else {
              assert(frames_retrieved_ + 1 == frames_to_get_);
            }
          }
          if (retriever_data_idx_ < encoded_data_.size()) {
            next_frame_.store(encoded_data_[retriever_data_idx_].valid_frames(
                                retriever_valid_idx_),
                              std::memory_order_release);
          }
          // printf("got frame %d\n", frames_retrieved_.load());
          total_frames_used++;
          frames_retrieved_++;
        } else {
          more_frames = decoder_->discard_frame();
        }
        current_frame_++;
        total_frames_decoded++;
        // printf("curr frame %d, frames decoded %d\n", current_frame_,
        //        total_frames_decoded);
      }
      if (profiler_) {
        profiler_->add_interval("iter", iter, now());
      }
    }
    std::this_thread::yield();
  }
  decoder_->wait_until_frames_copied();
  if (profiler_) {
    profiler_->add_interval("get_frames", start, now());
    profiler_->increment("frames_used", total_frames_used);
    profiler_->increment("frames_decoded", total_frames_decoded);
  }
}

void DecoderAutomata::set_profiler(Profiler* profiler) {
  profiler_ = profiler;
  decoder_->set_profiler(profiler);
}

void DecoderAutomata::feeder() {
  // printf("feeder start\n");
  i64 total_frames_fed = 0;
  i32 frames_fed = 0;
  seeking_ = false;
  while (not_done_) {
    {
      // Wait until frames are being requested
      std::unique_lock<std::mutex> lk(feeder_mutex_);
      feeder_waiting_ = true;
    }
    wake_feeder_.notify_one();

    {
      std::unique_lock<std::mutex> lk(feeder_mutex_);
      wake_feeder_.wait(lk, [this] { return !feeder_waiting_; });
    }
    std::atomic_thread_fence(std::memory_order_acquire);

    // Ignore requests to feed if we have alredy fed all data
    if (encoded_data_.size() <= feeder_data_idx_) {
      continue;
    }

    if (seeking_) {
      decoder_->feed(nullptr, 0, true);
      seeking_ = false;
    }

    if (profiler_) {
      profiler_->increment("frames_fed", frames_fed);
    }
    frames_fed = 0;
    bool seen_metadata = false;
    while (frames_retrieved_ < frames_to_get_) {
      i32 frames_to_wait = 8;
      while (frames_retrieved_ < frames_to_get_ &&
             decoder_->decoded_frames_buffered() > frames_to_wait) {
        wake_feeder_.notify_one();
        std::this_thread::yield();
      }
      if (skip_frames_) {
        seen_metadata = false;
        seeking_ = true;
        set_feeder_idx(feeder_data_idx_ + 1);
        break;
      }
      frames_fed++;

      i32 fdi = feeder_data_idx_.load(std::memory_order_acquire);
      const u8* encoded_buffer =
        (const u8*)encoded_data_[fdi].mutable_encoded_video()->data();
      size_t encoded_buffer_size =
        encoded_data_[fdi].mutable_encoded_video()->size();
      i32 encoded_packet_size = 0;
      const u8* encoded_packet = NULL;
      if (feeder_buffer_offset_ < encoded_buffer_size) {
        encoded_packet_size =
          *reinterpret_cast<const i32*>(encoded_buffer + feeder_buffer_offset_);
        feeder_buffer_offset_ += sizeof(i32);
        encoded_packet = encoded_buffer + feeder_buffer_offset_;
        assert(encoded_packet_size < encoded_buffer_size);
        feeder_buffer_offset_ += encoded_packet_size;
        // printf("encoded packet size %d, ptr %p\n", encoded_packet_size,
        //        encoded_packet);
      }

      if (seen_metadata && encoded_packet_size > 0) {
        const u8* start_buffer = encoded_packet;
        i32 original_size = encoded_packet_size;

        while (encoded_packet_size > 0) {
          const u8* nal_start;
          i32 nal_size;
          next_nal(encoded_packet, encoded_packet_size, nal_start, nal_size);
          if (encoded_packet_size == 0) {
            break;
          }
          i32 nal_type = get_nal_unit_type(nal_start);
          i32 nal_ref = get_nal_ref_idc(nal_start);
          if (is_vcl_nal(nal_type)) {
            encoded_packet = nal_start -= 3;
            encoded_packet_size = nal_size + encoded_packet_size + 3;
            break;
          }
        }
      }

      decoder_->feed(encoded_packet, encoded_packet_size, false);

      if (feeder_current_frame_ == feeder_next_frame_) {
        feeder_valid_idx_++;
        if (feeder_valid_idx_ <
            encoded_data_[feeder_data_idx_].valid_frames_size()) {
          feeder_next_frame_ =
            encoded_data_[feeder_data_idx_].valid_frames(feeder_valid_idx_);
        } else {
          // Done
          feeder_next_frame_ = -1;
        }
      }
      feeder_current_frame_++;

      // Set a discontinuity if we sent an empty packet to reset
      // the stream next time
      if (encoded_packet_size == 0) {
        assert(feeder_buffer_offset_ >= encoded_buffer_size);
        // Reached the end of a decoded segment so wait for decoder to flush
        // before moving onto next segment
        seen_metadata = false;
        seeking_ = true;
        set_feeder_idx(feeder_data_idx_ + 1);
        break;
      } else {
        seen_metadata = true;
      }
      std::this_thread::yield();
    }
    // printf("frames fed %d\n", frames_fed);
  }
}

void DecoderAutomata::set_feeder_idx(i32 data_idx) {
  feeder_data_idx_ = data_idx;
  feeder_valid_idx_ = 0;
  feeder_buffer_offset_ = 0;
  if (feeder_data_idx_ < encoded_data_.size()) {
    feeder_current_frame_ = encoded_data_[feeder_data_idx_].keyframes(0);
    feeder_next_frame_ = encoded_data_[feeder_data_idx_].valid_frames(0);
    feeder_next_keyframe_ = encoded_data_[feeder_data_idx_].keyframes(1);
  }
}
}
}
<commit_msg>Fix race condition in decoder and reading invalid frames after seek<commit_after>/* Copyright 2016 Carnegie Mellon University
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include "scanner/video/decoder_automata.h"
#include "scanner/metadata.pb.h"

#include "scanner/util/h264.h"
#include "scanner/util/memory.h"

#include <thread>

namespace scanner {
namespace internal {

DecoderAutomata::DecoderAutomata(DeviceHandle device_handle, i32 num_devices,
                                 VideoDecoderType decoder_type)
  : device_handle_(device_handle),
    num_devices_(num_devices),
    decoder_type_(decoder_type),
    decoder_(
      VideoDecoder::make_from_config(device_handle, num_devices, decoder_type)),
    feeder_waiting_(false),
    not_done_(true),
    frames_retrieved_(0),
    skip_frames_(false) {
  feeder_thread_ = std::thread(&DecoderAutomata::feeder, this);
}

DecoderAutomata::~DecoderAutomata() {
  {
    frames_to_get_ = 0;
    frames_retrieved_ = 0;
    while (decoder_->discard_frame()) {
    }

    std::unique_lock<std::mutex> lk(feeder_mutex_);
    wake_feeder_.wait(lk, [this] { return feeder_waiting_.load(); });

    if (frames_retrieved_ > 0) {
      decoder_->feed(nullptr, 0, true);
    }
    not_done_ = false;
    feeder_waiting_ = false;
  }
  wake_feeder_.notify_one();
  feeder_thread_.join();
}

void DecoderAutomata::initialize(
  const std::vector<proto::DecodeArgs>& encoded_data) {
  assert(!encoded_data.empty());
  encoded_data_ = encoded_data;
  frame_size_ = encoded_data[0].width() * encoded_data[0].height() * 3;
  current_frame_ = encoded_data[0].start_keyframe();
  next_frame_.store(encoded_data[0].valid_frames(0), std::memory_order_release);
  retriever_data_idx_.store(0, std::memory_order_release);
  retriever_valid_idx_ = 0;

  FrameInfo info;
  info.set_width(encoded_data[0].width());
  info.set_height(encoded_data[0].height());

  while (decoder_->discard_frame()) {
  }

  std::unique_lock<std::mutex> lk(feeder_mutex_);
  wake_feeder_.wait(lk, [this] { return feeder_waiting_.load(); });

  if (info_.width() != info.width() || info_.height() != info.height()) {
    decoder_->configure(info);
  }
  if (frames_retrieved_ > 0) {
    decoder_->feed(nullptr, 0, true);
  }

  set_feeder_idx(0);
  info_ = info;
  std::atomic_thread_fence(std::memory_order_release);
  seeking_ = false;
}

void DecoderAutomata::get_frames(u8* buffer, i32 num_frames) {
  i64 total_frames_decoded = 0;
  i64 total_frames_used = 0;

  auto start = now();

  // Wait until feeder is waiting
  {
    // Wait until frames are being requested
    std::unique_lock<std::mutex> lk(feeder_mutex_);
    wake_feeder_.wait(lk, [this] { return feeder_waiting_.load(); });
  }

  if (seeking_) {
    decoder_->feed(nullptr, 0, true);
    seeking_ = false;
  }

  // Start up feeder thread
  {
    std::unique_lock<std::mutex> lk(feeder_mutex_);
    frames_retrieved_ = 0;
    frames_to_get_ = num_frames;
    feeder_waiting_ = false;
  }
  wake_feeder_.notify_one();

  if (profiler_) {
    profiler_->add_interval("get_frames_wait", start, now());
  }

  while (frames_retrieved_ < frames_to_get_) {
    if (decoder_->decoded_frames_buffered() > 0) {
      auto iter = now();
      // New frames
      bool more_frames = true;
      while (more_frames && frames_retrieved_ < frames_to_get_) {
        const auto& valid_frames =
          encoded_data_[retriever_data_idx_].valid_frames();
        assert(valid_frames.size() > retriever_valid_idx_.load());
        assert(current_frame_ <= valid_frames.Get(retriever_valid_idx_));
        // printf("has buffered frames, curr %d, next %d\n",
        //        current_frame_, valid_frames.Get(retriever_valid_idx_));

        if (current_frame_ == valid_frames.Get(retriever_valid_idx_)) {
          u8* decoded_buffer = buffer + frames_retrieved_ * frame_size_;
          more_frames = decoder_->get_frame(decoded_buffer, frame_size_);
          retriever_valid_idx_++;
          if (retriever_valid_idx_ == valid_frames.size()) {
            // Move to next decode args
            retriever_data_idx_ += 1;
            retriever_valid_idx_ = 0;

            // Trigger feeder to start again and set ourselves to the
            // start of that keyframe
            if (retriever_data_idx_ < encoded_data_.size()) {
              {
                // Wait until feeder is waiting
                // skip_frames_ = true;
                std::unique_lock<std::mutex> lk(feeder_mutex_);
                wake_feeder_.wait(lk, [this, &total_frames_decoded] {
                  while (decoder_->discard_frame()) {
                    total_frames_decoded++;
                  }
                  return feeder_waiting_.load();
                });
                // skip_frames_ = false;
              }

              if (seeking_) {
                decoder_->feed(nullptr, 0, true);
                seeking_ = false;
              }

              {
                std::unique_lock<std::mutex> lk(feeder_mutex_);
                feeder_waiting_ = false;
                current_frame_ =
                  encoded_data_[retriever_data_idx_].keyframes(0) - 1;
              }
              wake_feeder_.notify_one();

              // We reset the decoder, so we should wait until there are more
              // frames in the buffer
              more_frames = false;
            } else {
              assert(frames_retrieved_ + 1 == frames_to_get_);
            }
          }
          if (retriever_data_idx_ < encoded_data_.size()) {
            next_frame_.store(encoded_data_[retriever_data_idx_].valid_frames(
                                retriever_valid_idx_),
                              std::memory_order_release);
          }
          // printf("got frame %d\n", frames_retrieved_.load());
          total_frames_used++;
          frames_retrieved_++;
        } else {
          more_frames = decoder_->discard_frame();
        }
        current_frame_++;
        total_frames_decoded++;
        // printf("curr frame %d, frames decoded %d\n", current_frame_,
        //        total_frames_decoded);
      }
      if (profiler_) {
        profiler_->add_interval("iter", iter, now());
      }
    }
    std::this_thread::yield();
  }
  decoder_->wait_until_frames_copied();
  if (profiler_) {
    profiler_->add_interval("get_frames", start, now());
    profiler_->increment("frames_used", total_frames_used);
    profiler_->increment("frames_decoded", total_frames_decoded);
  }
}

void DecoderAutomata::set_profiler(Profiler* profiler) {
  profiler_ = profiler;
  decoder_->set_profiler(profiler);
}

void DecoderAutomata::feeder() {
  // printf("feeder start\n");
  i64 total_frames_fed = 0;
  i32 frames_fed = 0;
  seeking_ = false;
  while (not_done_) {
    {
      // Wait until frames are being requested
      std::unique_lock<std::mutex> lk(feeder_mutex_);
      feeder_waiting_ = true;
    }
    wake_feeder_.notify_one();

    {
      std::unique_lock<std::mutex> lk(feeder_mutex_);
      wake_feeder_.wait(lk, [this] { return !feeder_waiting_; });
    }
    std::atomic_thread_fence(std::memory_order_acquire);

    // Ignore requests to feed if we have alredy fed all data
    if (encoded_data_.size() <= feeder_data_idx_) {
      continue;
    }

    if (seeking_) {
      decoder_->feed(nullptr, 0, true);
      seeking_ = false;
    }

    if (profiler_) {
      profiler_->increment("frames_fed", frames_fed);
    }
    frames_fed = 0;
    bool seen_metadata = false;
    while (frames_retrieved_ < frames_to_get_) {
      i32 frames_to_wait = 8;
      while (frames_retrieved_ < frames_to_get_ &&
             decoder_->decoded_frames_buffered() > frames_to_wait) {
        wake_feeder_.notify_one();
        std::this_thread::yield();
      }
      if (skip_frames_) {
        seen_metadata = false;
        seeking_ = true;
        set_feeder_idx(feeder_data_idx_ + 1);
        break;
      }
      frames_fed++;

      i32 fdi = feeder_data_idx_.load(std::memory_order_acquire);
      const u8* encoded_buffer =
        (const u8*)encoded_data_[fdi].mutable_encoded_video()->data();
      size_t encoded_buffer_size =
        encoded_data_[fdi].mutable_encoded_video()->size();
      i32 encoded_packet_size = 0;
      const u8* encoded_packet = NULL;
      if (feeder_buffer_offset_ < encoded_buffer_size) {
        encoded_packet_size =
          *reinterpret_cast<const i32*>(encoded_buffer + feeder_buffer_offset_);
        feeder_buffer_offset_ += sizeof(i32);
        encoded_packet = encoded_buffer + feeder_buffer_offset_;
        assert(encoded_packet_size < encoded_buffer_size);
        feeder_buffer_offset_ += encoded_packet_size;
        // printf("encoded packet size %d, ptr %p\n", encoded_packet_size,
        //        encoded_packet);
      }

      if (seen_metadata && encoded_packet_size > 0) {
        const u8* start_buffer = encoded_packet;
        i32 original_size = encoded_packet_size;

        while (encoded_packet_size > 0) {
          const u8* nal_start;
          i32 nal_size;
          next_nal(encoded_packet, encoded_packet_size, nal_start, nal_size);
          if (encoded_packet_size == 0) {
            break;
          }
          i32 nal_type = get_nal_unit_type(nal_start);
          i32 nal_ref = get_nal_ref_idc(nal_start);
          if (is_vcl_nal(nal_type)) {
            encoded_packet = nal_start -= 3;
            encoded_packet_size = nal_size + encoded_packet_size + 3;
            break;
          }
        }
      }

      decoder_->feed(encoded_packet, encoded_packet_size, false);

      if (feeder_current_frame_ == feeder_next_frame_) {
        feeder_valid_idx_++;
        if (feeder_valid_idx_ <
            encoded_data_[feeder_data_idx_].valid_frames_size()) {
          feeder_next_frame_ =
            encoded_data_[feeder_data_idx_].valid_frames(feeder_valid_idx_);
        } else {
          // Done
          feeder_next_frame_ = -1;
        }
      }
      feeder_current_frame_++;

      // Set a discontinuity if we sent an empty packet to reset
      // the stream next time
      if (encoded_packet_size == 0) {
        assert(feeder_buffer_offset_ >= encoded_buffer_size);
        // Reached the end of a decoded segment so wait for decoder to flush
        // before moving onto next segment
        seen_metadata = false;
        seeking_ = true;
        set_feeder_idx(feeder_data_idx_ + 1);
        break;
      } else {
        seen_metadata = true;
      }
      std::this_thread::yield();
    }
    // printf("frames fed %d\n", frames_fed);
  }
}

void DecoderAutomata::set_feeder_idx(i32 data_idx) {
  feeder_data_idx_ = data_idx;
  feeder_valid_idx_ = 0;
  feeder_buffer_offset_ = 0;
  if (feeder_data_idx_ < encoded_data_.size()) {
    feeder_current_frame_ = encoded_data_[feeder_data_idx_].keyframes(0);
    feeder_next_frame_ = encoded_data_[feeder_data_idx_].valid_frames(0);
    feeder_next_keyframe_ = encoded_data_[feeder_data_idx_].keyframes(1);
  }
}
}
}
<|endoftext|>


<commit_before>#include "CASCImage.h"

#include "../DesktopEditor/raster/Metafile/MetaFile.h"
#include "../DesktopEditor/graphics/Image.h"

#if defined(_WIN32) || defined (_WIN64)

#else
	#include <unistd.h>
#endif

namespace NSHtmlRenderer
{
    CASCImage::CASCImage(CApplicationFonts *pAppFonts)
	{
        m_pMetafile		= new MetaFile::CMetaFile(pAppFonts);
		m_pMediaData	= NULL;

        m_bLoadOnlyMeta = false;

		m_lImageType = c_lImageTypeUnknown;

		m_dDpiX = 72;
		m_dDpiY = 72;

		m_wsTempFilePath.Empty();
	}
	CASCImage::~CASCImage()
	{
		Close();
		RELEASEOBJECT(m_pMetafile);
	}
	void CASCImage::Open(const std::wstring& bsFilePath)
	{
		// Закроем раннее открытый файл (если он был открыт)
		Close();

		if (m_pMetafile == NULL) return;

		// Сначала попытаемя открыть файл как WMF/EMF

		if ( m_pMetafile->LoadFromFile( bsFilePath.c_str() ) == true )
		{
			// Файл открылся нормально
			long MetaType = m_pMetafile->GetType();

			m_lImageType =  c_lImageTypeMetafile | MetaType;
			if (MetaType == c_lMetaWmf) return;

//#if !defined(_WIN32) && !defined (_WIN64)			// emf всеже под win лучше читать через gdi+
			if (MetaType == c_lMetaEmf) return;
//#endif
		}
		// Это не Wmf & Emf
		m_pMetafile->Close();

		{
			m_pMediaData = new Aggplus::CImage(bsFilePath);
            if(Aggplus::Ok == m_pMediaData->GetLastStatus())
				m_lImageType = c_lImageTypeBitmap;
			else
				m_pMediaData = NULL;
		}
		return;
	}

	void CASCImage::Close()
	{
		if ( m_lImageType & c_lImageTypeMetafile )
		{
			m_pMetafile->Close();

			if ( m_lImageType & c_lMetaEmf )
			{
				// Удаляем временный файл
				//todo может проверять не пустой ли m_wsTempFilePath, а не m_lImageType & c_lMetaEmf
#if defined(_WIN32) || defined (_WIN64)
                ::_wunlink( m_wsTempFilePath.GetBuffer() );
#else
                std::string sTempFilePath = NSFile::CUtf8Converter::GetUtf8StringFromUnicode2(m_wsTempFilePath.c_str(), m_wsTempFilePath.length());
                ::unlink( sTempFilePath.c_str() );
#endif

			}
		}

		m_lImageType = c_lImageTypeUnknown;
		m_wsTempFilePath = _T("");

		RELEASEOBJECT(m_pMediaData);
	}
	HRESULT CASCImage::get_Type(LONG* lType)
	{
		if (NULL != lType)
			*lType = m_lImageType;

		return S_OK;
	}
	HRESULT CASCImage::get_Width(LONG* lWidth)
	{
		if ( NULL != lWidth )
		{
			if (NULL != m_pMediaData)
			{
				*lWidth = m_pMediaData->GetWidth();
			}
			else if ( (c_lImageTypeMetafile | c_lMetaWmf) == m_lImageType || (c_lImageTypeMetafile | c_lMetaEmf) == m_lImageType )
			{
				double x=0, y=0, w=0, h=0;
				m_pMetafile->GetBounds(&x,&y,&w,&h);
				*lWidth = (LONG)w;
			}
			else
			{
				*lWidth = 0;
			}
		}

		return S_OK;
	}
	HRESULT CASCImage::put_Width(LONG lWidth)
	{
		return S_OK;
	}
	HRESULT CASCImage::get_Height(LONG* lHeight)
	{
		if ( NULL != lHeight )
		{
			if (NULL != m_pMediaData)
			{
				*lHeight = m_pMediaData->GetHeight();
			}
			else if ( (c_lImageTypeMetafile | c_lMetaWmf) == m_lImageType || (c_lImageTypeMetafile | c_lMetaEmf) == m_lImageType )
			{
				double x=0, y=0, w=0, h=0;
				m_pMetafile->GetBounds(&x,&y,&w,&h);
				*lHeight = (LONG)h;
			}
			else
			{
				*lHeight = 0;
			}
		}

		return S_OK;
	}
	HRESULT CASCImage::put_Height(LONG lHeight)
	{
		return S_OK;
	}
	HRESULT CASCImage::get_DpiX(double* dDpiX)
	{
		*dDpiX = m_dDpiX;
		return S_OK;
	}
	HRESULT CASCImage::put_DpiX(double dDpiX)
	{
		m_dDpiX = dDpiX;
		return S_OK;
	}
	HRESULT CASCImage::get_DpiY(double* dDpiY)
	{
		*dDpiY = m_dDpiY;
		return S_OK;
	}
	HRESULT CASCImage::put_DpiY(double dDpiY)
	{
		m_dDpiY = dDpiY;
		return S_OK;
	}
	HRESULT CASCImage::LoadFromFile(const std::wstring& bsFilePath)
	{
		// Внутри комманды Open выполняется команда Close
		Open( bsFilePath );

		return S_OK;
	}
	HRESULT CASCImage::DrawOnRenderer(IRenderer* pRenderer, double dX, double dY, double dWidth, double dHeight)
	{
		if (NULL == pRenderer)
			return S_FALSE;

		pRenderer->BeginCommand(c_nImageType);

		if ( NULL != m_pMediaData )
		{
			pRenderer->DrawImage(m_pMediaData, dX, dY, dWidth, dHeight);
		}
		else if ( (c_lImageTypeMetafile | c_lMetaWmf) == m_lImageType ||
					(c_lImageTypeMetafile | c_lMetaEmf) == m_lImageType )
		{
			m_pMetafile->DrawOnRenderer(pRenderer, dX, dY, dWidth, dHeight);
		}

		pRenderer->EndCommand(c_nImageType);
		return S_OK;
	}

	//-------------------------------------------------------------------------------------------
	//   IASCGraphicsBase
	//-------------------------------------------------------------------------------------------
	HRESULT CASCImage::LoadOnlyMeta(bool bVal)
	{
		m_bLoadOnlyMeta = bVal;
		return S_OK;
	}
	HRESULT CASCImage::LoadSVG(const std::wstring& sVal)
	{
		//Close();
		//CoCreateInstance( __uuidof(SVGTransformer), NULL, CLSCTX_ALL, __uuidof(ISVGTransformer), (void**)(&m_pSVGFile) );
		//if (NULL != m_pSVGFile)
		//{
		//	if ( AVS_ERROR_FILEFORMAT == m_pSVGFile->Load( ParamValue.bstrVal ) )
		//	{
		//		RELEASEINTERFACE( m_pSVGFile );
		//		return S_FALSE;
		//	}
		//	else
		//	{
		//		m_lImageType = c_lImageTypeMetafile | c_lMetaSVG;
		//	}
		//}
		return S_OK;
	}
	CFontManager* CASCImage::get_FontManager()
	{
		return m_pMetafile->get_FontManager();
	}

	Aggplus::CImage* CASCImage::get_BitmapImage()
	{
		return m_pMediaData;
	}
}
<commit_msg>to Revision: 65026<commit_after>#include "CASCImage.h"

#include "../DesktopEditor/raster/Metafile/MetaFile.h"
#include "../DesktopEditor/graphics/Image.h"

#if defined(_WIN32) || defined (_WIN64)

#else
	#include <unistd.h>
#endif

namespace NSHtmlRenderer
{
    CASCImage::CASCImage(CApplicationFonts *pAppFonts)
	{
        m_pMetafile		= new MetaFile::CMetaFile(pAppFonts);
		m_pMediaData	= NULL;

        m_bLoadOnlyMeta = false;

		m_lImageType = c_lImageTypeUnknown;

		m_dDpiX = 72;
		m_dDpiY = 72;

		m_wsTempFilePath.Empty();
	}
	CASCImage::~CASCImage()
	{
		Close();
		RELEASEOBJECT(m_pMetafile);
	}
	void CASCImage::Open(const std::wstring& bsFilePath)
	{
		// Закроем раннее открытый файл (если он был открыт)
		Close();

		if (m_pMetafile == NULL) return;

		// Сначала попытаемя открыть файл как WMF/EMF

		if ( m_pMetafile->LoadFromFile( bsFilePath.c_str() ) == true )
		{
			// Файл открылся нормально
			long MetaType = m_pMetafile->GetType();

			m_lImageType =  c_lImageTypeMetafile | MetaType;
			if (MetaType == c_lMetaWmf) return;

//#if !defined(_WIN32) && !defined (_WIN64)			// emf всеже под win лучше читать через gdi+
			if (MetaType == c_lMetaEmf) return;
//#endif
		}
		// Это не Wmf & Emf
		m_pMetafile->Close();

		{
			m_pMediaData = new Aggplus::CImage(bsFilePath);
            if(Aggplus::Ok == m_pMediaData->GetLastStatus())
				m_lImageType = c_lImageTypeBitmap;
			else
				m_pMediaData = NULL;
		}
		return;
	}

	void CASCImage::Close()
	{
		if ( m_lImageType & c_lImageTypeMetafile )
		{
			m_pMetafile->Close();

			if ( m_lImageType & c_lMetaEmf )
			{
				// Удаляем временный файл
				//todo может проверять не пустой ли m_wsTempFilePath, а не m_lImageType & c_lMetaEmf
#if defined(_WIN32) || defined (_WIN64)
                ::_wunlink( m_wsTempFilePath.GetBuffer() );
#else
                std::string sTempFilePath = NSFile::CUtf8Converter::GetUtf8StringFromUnicode2(m_wsTempFilePath.c_str(), m_wsTempFilePath.length());
                ::unlink( sTempFilePath.c_str() );
#endif

			}
		}

		m_lImageType = c_lImageTypeUnknown;
		m_wsTempFilePath = _T("");

		RELEASEOBJECT(m_pMediaData);
	}
	HRESULT CASCImage::get_Type(LONG* lType)
	{
		if (NULL != lType)
			*lType = m_lImageType;

		return S_OK;
	}
	HRESULT CASCImage::get_Width(LONG* lWidth)
	{
		if ( NULL != lWidth )
		{
			if (NULL != m_pMediaData)
			{
				*lWidth = m_pMediaData->GetWidth();
			}
			else if ( (c_lImageTypeMetafile | c_lMetaWmf) == m_lImageType || (c_lImageTypeMetafile | c_lMetaEmf) == m_lImageType )
			{
				double x=0, y=0, w=0, h=0;
				m_pMetafile->GetBounds(&x,&y,&w,&h);
				*lWidth = (LONG)w;
			}
			else
			{
				*lWidth = 0;
			}
		}

		return S_OK;
	}
	HRESULT CASCImage::put_Width(LONG lWidth)
	{
		return S_OK;
	}
	HRESULT CASCImage::get_Height(LONG* lHeight)
	{
		if ( NULL != lHeight )
		{
			if (NULL != m_pMediaData)
			{
				*lHeight = m_pMediaData->GetHeight();
			}
			else if ( (c_lImageTypeMetafile | c_lMetaWmf) == m_lImageType || (c_lImageTypeMetafile | c_lMetaEmf) == m_lImageType )
			{
				double x=0, y=0, w=0, h=0;
				m_pMetafile->GetBounds(&x,&y,&w,&h);
				*lHeight = (LONG)h;
			}
			else
			{
				*lHeight = 0;
			}
		}

		return S_OK;
	}
	HRESULT CASCImage::put_Height(LONG lHeight)
	{
		return S_OK;
	}
	HRESULT CASCImage::get_DpiX(double* dDpiX)
	{
		*dDpiX = m_dDpiX;
		return S_OK;
	}
	HRESULT CASCImage::put_DpiX(double dDpiX)
	{
		m_dDpiX = dDpiX;
		return S_OK;
	}
	HRESULT CASCImage::get_DpiY(double* dDpiY)
	{
		*dDpiY = m_dDpiY;
		return S_OK;
	}
	HRESULT CASCImage::put_DpiY(double dDpiY)
	{
		m_dDpiY = dDpiY;
		return S_OK;
	}
	HRESULT CASCImage::LoadFromFile(const std::wstring& bsFilePath)
	{
		// Внутри комманды Open выполняется команда Close
		Open( bsFilePath );

		return S_OK;
	}
	HRESULT CASCImage::DrawOnRenderer(IRenderer* pRenderer, double dX, double dY, double dWidth, double dHeight)
	{
		if (NULL == pRenderer)
			return S_FALSE;

		pRenderer->BeginCommand(c_nImageType);

		if ( NULL != m_pMediaData )
		{
			pRenderer->DrawImage(m_pMediaData, dX, dY, dWidth, dHeight);
		}
		else if ( (c_lImageTypeMetafile | c_lMetaWmf) == m_lImageType ||
					(c_lImageTypeMetafile | c_lMetaEmf) == m_lImageType )
		{
			m_pMetafile->DrawOnRenderer(pRenderer, dX, dY, dWidth, dHeight);
		}

		pRenderer->EndCommand(c_nImageType);
		return S_OK;
	}

	//-------------------------------------------------------------------------------------------
	//   IASCGraphicsBase
	//-------------------------------------------------------------------------------------------
	HRESULT CASCImage::LoadOnlyMeta(bool bVal)
	{
		m_bLoadOnlyMeta = bVal;
		return S_OK;
	}
	HRESULT CASCImage::LoadSVG(const std::wstring& sVal)
	{
		//Close();
		//CoCreateInstance( __uuidof(SVGTransformer), NULL, CLSCTX_ALL, __uuidof(ISVGTransformer), (void**)(&m_pSVGFile) );
		//if (NULL != m_pSVGFile)
		//{
		//	if ( AVS_ERROR_FILEFORMAT == m_pSVGFile->Load( ParamValue.bstrVal ) )
		//	{
		//		RELEASEINTERFACE( m_pSVGFile );
		//		return S_FALSE;
		//	}
		//	else
		//	{
		//		m_lImageType = c_lImageTypeMetafile | c_lMetaSVG;
		//	}
		//}
		return S_OK;
	}
	CFontManager* CASCImage::get_FontManager()
	{
		return m_pMetafile->get_FontManager();
	}
	void CASCImage::put_FontManager(CFontManager* pManager)
	{
		//ничего не делаем, потому что CFontManager пришел в конструкторе.
	}

	Aggplus::CImage* CASCImage::get_BitmapImage()
	{
		return m_pMediaData;
	}
}
<|endoftext|>


<commit_before>/*************************************************************************
 *
 *  OpenOffice.org - a multi-platform office productivity suite
 *
 *  $RCSfile: TextObjectBar.hxx,v $
 *
 *  $Revision: 1.5 $
 *
 *  last change: $Author: kz $ $Date: 2006-12-12 17:39:12 $
 *
 *  The Contents of this file are made available subject to
 *  the terms of GNU Lesser General Public License Version 2.1.
 *
 *
 *    GNU Lesser General Public License Version 2.1
 *    =============================================
 *    Copyright 2005 by Sun Microsystems, Inc.
 *    901 San Antonio Road, Palo Alto, CA 94303, USA
 *
 *    This library is free software; you can redistribute it and/or
 *    modify it under the terms of the GNU Lesser General Public
 *    License version 2.1, as published by the Free Software Foundation.
 *
 *    This library is distributed in the hope that it will be useful,
 *    but WITHOUT ANY WARRANTY; without even the implied warranty of
 *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 *    Lesser General Public License for more details.
 *
 *    You should have received a copy of the GNU Lesser General Public
 *    License along with this library; if not, write to the Free Software
 *    Foundation, Inc., 59 Temple Place, Suite 330, Boston,
 *    MA  02111-1307  USA
 *
 ************************************************************************/

#ifndef SD_TEXT_OBJECT_BAR_HXX
#define SD_TEXT_OBJECT_BAR_HXX

#ifndef _SFXMODULE_HXX //autogen
#include <sfx2/module.hxx>
#endif
#ifndef _SFX_SHELL_HXX //autogen
#include <sfx2/shell.hxx>
#endif

#ifndef _SD_GLOB_HXX
#include "glob.hxx"
#endif

class CommandEvent;

namespace sd {

class View;
class ViewShell;
class Window;

class TextObjectBar
    : public SfxShell
{
public:
    TYPEINFO();
    SFX_DECL_INTERFACE(SD_IF_SDDRAWTEXTOBJECTBAR)

    TextObjectBar (
        ViewShell* pSdViewShell,
        SfxItemPool& rItemPool,
        ::sd::View* pSdView);
    virtual ~TextObjectBar (void);

    void GetAttrState( SfxItemSet& rSet );
    void Execute( SfxRequest &rReq );

    virtual void Command( const CommandEvent& rCEvt );

private:
    ViewShell* mpViewShell;
    ::sd::View* mpView;
};

} // end of namespace sd

#endif
<commit_msg>INTEGRATION: CWS changefileheader (1.5.298); FILE MERGED 2008/04/01 15:35:18 thb 1.5.298.2: #i85898# Stripping all external header guards 2008/03/31 13:58:11 rt 1.5.298.1: #i87441# Change license header to LPGL v3.<commit_after>/*************************************************************************
 *
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
 *
 * Copyright 2008 by Sun Microsystems, Inc.
 *
 * OpenOffice.org - a multi-platform office productivity suite
 *
 * $RCSfile: TextObjectBar.hxx,v $
 * $Revision: 1.6 $
 *
 * This file is part of OpenOffice.org.
 *
 * OpenOffice.org is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License version 3
 * only, as published by the Free Software Foundation.
 *
 * OpenOffice.org is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Lesser General Public License version 3 for more details
 * (a copy is included in the LICENSE file that accompanied this code).
 *
 * You should have received a copy of the GNU Lesser General Public License
 * version 3 along with OpenOffice.org.  If not, see
 * <http://www.openoffice.org/license.html>
 * for a copy of the LGPLv3 License.
 *
 ************************************************************************/

#ifndef SD_TEXT_OBJECT_BAR_HXX
#define SD_TEXT_OBJECT_BAR_HXX

#include <sfx2/module.hxx>
#include <sfx2/shell.hxx>
#include "glob.hxx"

class CommandEvent;

namespace sd {

class View;
class ViewShell;
class Window;

class TextObjectBar
    : public SfxShell
{
public:
    TYPEINFO();
    SFX_DECL_INTERFACE(SD_IF_SDDRAWTEXTOBJECTBAR)

    TextObjectBar (
        ViewShell* pSdViewShell,
        SfxItemPool& rItemPool,
        ::sd::View* pSdView);
    virtual ~TextObjectBar (void);

    void GetAttrState( SfxItemSet& rSet );
    void Execute( SfxRequest &rReq );

    virtual void Command( const CommandEvent& rCEvt );

private:
    ViewShell* mpViewShell;
    ::sd::View* mpView;
};

} // end of namespace sd

#endif
<|endoftext|>


<commit_before>// Copyright (C) 2008 Till Busch buti@bux.at
//
// 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 2 of the
// License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful, but
// WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
// General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.

#include <osgDB/ReadFile>

#include <simgear/debug/logstream.hxx>
#include <simgear/structure/OSGVersion.hxx>

#include "modellib.hxx"
#include "SGReaderWriterXMLOptions.hxx"
#include "SGPagedLOD.hxx"

using namespace osg;
using namespace simgear;

SGPagedLOD::SGPagedLOD()
        : PagedLOD()
{
}

SGPagedLOD::~SGPagedLOD()
{
    //SG_LOG(SG_GENERAL, SG_ALERT, "SGPagedLOD::~SGPagedLOD(" << getFileName(0) << ")");
}

SGPagedLOD::SGPagedLOD(const SGPagedLOD& plod,const CopyOp& copyop)
        : osg::PagedLOD(plod, copyop),
        _readerWriterOptions(plod._readerWriterOptions)
{
}

bool SGPagedLOD::addChild(osg::Node *child)
{
    //SG_LOG(SG_GENERAL, SG_ALERT, "SGPagedLOD::addChild(" << getFileName(getNumChildren()) << ")");
    if (!PagedLOD::addChild(child))
        return false;

    setRadius(getBound().radius());
    setCenter(getBound().center());
    SGReaderWriterXMLOptions* opts;
    opts = dynamic_cast<SGReaderWriterXMLOptions*>(_readerWriterOptions.get());
    if(opts)
    {
        osg::ref_ptr<SGModelData> d = opts->getModelData();
        if(d.valid())
            d->modelLoaded(getFileName(getNumChildren()-1), 0, this);
    }
    return true;
}

void SGPagedLOD::forceLoad(osgDB::DatabasePager *dbp)
{
    //SG_LOG(SG_GENERAL, SG_ALERT, "SGPagedLOD::forceLoad(" <<
    //getFileName(getNumChildren()) << ")");
    unsigned childNum = getNumChildren();
    setTimeStamp(childNum, 0);
    double priority=1.0;
    dbp->requestNodeFile(getFileName(childNum),this,priority,0,
                         getDatabaseRequest(childNum),
                         _readerWriterOptions.get());
}

<commit_msg>Give the models properties as an argument to the init callback.<commit_after>// Copyright (C) 2008 Till Busch buti@bux.at
//
// 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 2 of the
// License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful, but
// WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
// General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.

#include <osgDB/ReadFile>

#include <simgear/debug/logstream.hxx>
#include <simgear/structure/OSGVersion.hxx>

#include "modellib.hxx"
#include "SGReaderWriterXMLOptions.hxx"
#include "SGPagedLOD.hxx"

using namespace osg;
using namespace simgear;

SGPagedLOD::SGPagedLOD()
        : PagedLOD()
{
}

SGPagedLOD::~SGPagedLOD()
{
    //SG_LOG(SG_GENERAL, SG_ALERT, "SGPagedLOD::~SGPagedLOD(" << getFileName(0) << ")");
}

SGPagedLOD::SGPagedLOD(const SGPagedLOD& plod,const CopyOp& copyop)
        : osg::PagedLOD(plod, copyop),
        _readerWriterOptions(plod._readerWriterOptions)
{
}

bool SGPagedLOD::addChild(osg::Node *child)
{
    //SG_LOG(SG_GENERAL, SG_ALERT, "SGPagedLOD::addChild(" << getFileName(getNumChildren()) << ")");
    if (!PagedLOD::addChild(child))
        return false;

    setRadius(getBound().radius());
    setCenter(getBound().center());
    SGReaderWriterXMLOptions* opts;
    opts = dynamic_cast<SGReaderWriterXMLOptions*>(_readerWriterOptions.get());
    if(opts)
    {
        osg::ref_ptr<SGModelData> d = opts->getModelData();
        if(d.valid())
            d->modelLoaded(getFileName(getNumChildren()-1), d->getProperties(),
                           this);
    }
    return true;
}

void SGPagedLOD::forceLoad(osgDB::DatabasePager *dbp)
{
    //SG_LOG(SG_GENERAL, SG_ALERT, "SGPagedLOD::forceLoad(" <<
    //getFileName(getNumChildren()) << ")");
    unsigned childNum = getNumChildren();
    setTimeStamp(childNum, 0);
    double priority=1.0;
    dbp->requestNodeFile(getFileName(childNum),this,priority,0,
                         getDatabaseRequest(childNum),
                         _readerWriterOptions.get());
}

<|endoftext|>


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

  Program:   NeuroLib (DTI command line tools)
  Language:  C++
  Date:      $Date: 2009-05-26 16:21:19 $
  Version:   $Revision: 1.6 $
  Author:    Casey Goodlett (gcasey@sci.utah.edu)

  Copyright (c)  Casey Goodlett. All rights reserved.
  See NeuroLibCopyright.txt or http://www.ia.unc.edu/dev/Copyright.htm 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.

=========================================================================*/
// STL includes
#include <string>
#include <iostream>
#include <fstream>

// boost includes
#include <boost/program_options/option.hpp>
#include <boost/program_options/options_description.hpp>
#include <boost/program_options/positional_options.hpp>
#include <boost/program_options/variables_map.hpp>
#include <boost/program_options/parsers.hpp>
#include <boost/program_options/cmdline.hpp>

// ITK includes
#include <itkDiffusionTensor3D.h>
#include <itkImageFileReader.h>
#include <itkImageFileWriter.h>
#include <itkTensorLinearInterpolateImageFunction.h>
#include <itkVectorLinearInterpolateImageFunction.h>
#include <itkVersion.h>

//#include "FiberCalculator.h"
#include "deformationfieldoperations.h"
#include "fiberio.h"
#include "dtitypes.h"

namespace po = boost::program_options;

int main(int argc, char* argv[])
{
  // Read program options/configuration
  po::options_description config("Usage: fiberprocess input-fiber [options]");
  config.add_options()
    ("help,h", "produce this help message")
    ("verbose,v", "produces verbose output")

    ("fiber-output,o", po::value<std::string>(), "Output fiber file.  May be warped or updated with new data depending on other options used.")
    ("h-field,H", po::value<std::string>(), "HField for warp and statistics lookup.  If this option is used tensor-volume must also be specified.")
    ("displacement-field", po::value<std::string>(), "Displacement field for warp and statistics lookup.  If this option is used tensor-volume must also be specified.")
    ("no-warp,n", "Do not warp the geometry of the tensors only obtain the new statistics")
    ("tensor-volume,T", po::value<std::string>(), "Interpolate tensor values from the given field")

    // ******  TODO **********
    ("voxelize,V", po::value<std::string>(),"Voxelize fiber into a label map (the labelmap filename is the argument of -V).  The tensor file must be specified using -T for information about the size, origin, spacing of the image.")
    ("voxelize-count-fibers", "Count number of fibers per-voxel instead of just setting to 1")
    ("voxel-label,l", po::value<ScalarPixelType>()->default_value(1),"Label for voxelized fiber")

    // Compute 1-D statistics
    // ("mean-statistics,s", po::value<std::string>(), "Write summary statistics to text file")
    // ******  TODO **********
    ;

  po::options_description hidden("Hidden options");
  hidden.add_options()
    ("fiber-file", po::value<std::string>(), "DTI fiber file")
    ;

  po::options_description all;
  all.add(config).add(hidden);

  po::positional_options_description p;
  p.add("fiber-file",1);

  po::variables_map vm;

  try
  {
    po::store(po::command_line_parser(argc, argv).
              options(all).positional(p).run(), vm);
    po::notify(vm);
  }
  catch (const po::error &e)
  {
    std::cout << "Parse error: " << std::endl;
    std::cout << config << std::endl;
    return EXIT_FAILURE;
  }

  // End option reading configuration

  // Display help if asked or program improperly called
  if(vm.count("help") || !vm.count("fiber-file"))
  {
    std::cout << config << std::endl;
    if(vm.count("help"))
    {
      std::cout << "Version $Revision: 1.6 $ "<< std::endl;
      std::cout << ITK_SOURCE_VERSION << std::endl;
      return EXIT_SUCCESS;
    }
    else
    {
      return EXIT_FAILURE;
    }
  }

  const bool VERBOSE = vm.count("verbose");

  // Reader fiber bundle
  GroupType::Pointer group = readFiberFile(vm["fiber-file"].as<std::string>());

  DeformationImageType::Pointer deformationfield(NULL);
  if(vm.count("h-field"))
    deformationfield = readDeformationField(vm["h-field"].as<std::string>(), HField);
  else if(vm.count("displacement-field"))
    deformationfield = readDeformationField(vm["displacement-field"].as<std::string>(), Displacement);
  else
    deformationfield = NULL;

  typedef itk::VectorLinearInterpolateImageFunction<DeformationImageType, double> DeformationInterpolateType;
  DeformationInterpolateType::Pointer definterp(NULL);
  if(deformationfield)
  {
    definterp = DeformationInterpolateType::New();
    definterp->SetInputImage(deformationfield);
  }

  // Setup new fiber bundle group
  GroupType::Pointer newgroup = GroupType::New();
  newgroup->SetId(0);

  ChildrenListType* children = group->GetChildren(0);

  if(VERBOSE)
    std::cout << "Getting spacing" << std::endl;

  // Get Spacing and offset from group
  double spacing[3];
  for(unsigned int i =0; i < 3; i++)
    spacing[i] = (group->GetSpacing())[i];
  newgroup->SetSpacing(spacing);

  itk::Vector<double, 3> sooffset;
  for(unsigned int i = 0; i < 3; i++)
    sooffset[i] = (group->GetObjectToParentTransform()->GetOffset())[i];
  newgroup->GetObjectToParentTransform()->SetOffset(sooffset.GetDataPointer());

  if(VERBOSE)
  {
    std::cout << "Group Spacing: " << spacing[0] << ", " << spacing[1] << ", " << spacing[2] << std::endl;
    std::cout << "Group Offset: " << sooffset[0] << ", " << sooffset[1]  << ", " << sooffset[2] << std::endl;
  }

  // Setup tensor file if available
  typedef itk::ImageFileReader<TensorImageType> TensorImageReader;
  typedef itk::TensorLinearInterpolateImageFunction<TensorImageType, double> TensorInterpolateType;
  TensorImageReader::Pointer tensorreader = NULL;
  TensorInterpolateType::Pointer tensorinterp = NULL;

  if(vm.count("tensor-volume"))
  {
    tensorreader = TensorImageReader::New();
    tensorinterp = TensorInterpolateType::New();

    tensorreader->SetFileName(vm["tensor-volume"].as<std::string>().c_str());
    try
    {
      tensorreader->Update();
      tensorinterp->SetInputImage(tensorreader->GetOutput());
    }
    catch(itk::ExceptionObject exp)
    {
      std::cerr << exp << std::endl;
      return EXIT_FAILURE;
    }
  }

  if(VERBOSE)
    std::cout << "Starting Loop" << std::endl;

  ChildrenListType::iterator it;
  unsigned int id = 1;

  // Need to allocate an image to write into for creating
  // the fiber label map
  IntImageType::Pointer labelimage;
  if(vm.count("voxelize"))
  {
    if(!vm.count("tensor-volume"))
    {
      std::cerr << "Must specify tensor file to copy image metadata for fiber voxelize." << std::endl;
      return EXIT_FAILURE;
    }
    tensorreader->GetOutput();
    labelimage = IntImageType::New();
    labelimage->SetSpacing(tensorreader->GetOutput()->GetSpacing());
    labelimage->SetOrigin(tensorreader->GetOutput()->GetOrigin());
    labelimage->SetDirection(tensorreader->GetOutput()->GetDirection());
    labelimage->SetRegions(tensorreader->GetOutput()->GetLargestPossibleRegion());
    labelimage->Allocate();
    labelimage->FillBuffer(0);
  }

  double newspacing[3];
  for(unsigned int i =0; i < 3; i++)
    newspacing[i] = spacing[i];

  if (vm.count("tensor-volume") || vm.count("voxelize"))
  {
    for(unsigned int i =0; i < 3; i++)
      newspacing[i] = 1;
    // fiber coordinates are newly in mm
  }

  // For each fiber
  for(it = children->begin(); it != children->end(); it++)
  {
    // Get Spacing and offset from fiber
    const double* fiberspacing = (*it).GetPointer()->GetSpacing();
    const itk::Vector<double, 3> fibersooffset = dynamic_cast<DTITubeType*>((*it).GetPointer())->GetObjectToParentTransform()->GetOffset();

    // TODO: mode for selecting which to use
    if ((fiberspacing[0] != spacing[0]) || (fiberspacing[1] != spacing[1]) || (fiberspacing[1] != spacing[1]) ||
	(sooffset[0] != fibersooffset[0]) || (sooffset[1] != fibersooffset[1]) || (sooffset[1] != fibersooffset[1]))
    {
      std::cout << "Fiber and group spacing/offset is not equal using the one from the fiber group." << std::endl;
      if(VERBOSE)
      {
	std::cout << "Fiber Spacing: " << fiberspacing[0] << ", " << fiberspacing[1] << ", " << fiberspacing[2] << std::endl;
	std::cout << "Fiber Offset: " << fibersooffset[0] << ", " << fibersooffset[1]  << ", " << fibersooffset[2] << std::endl;
      }
      for(unsigned int i =0; i < 3; i++)
      {
	spacing[i] = fiberspacing[i];
	sooffset[i] = fibersooffset[i];
      }
      newgroup->SetSpacing(spacing);
      newgroup->GetObjectToParentTransform()->SetOffset(sooffset.GetDataPointer());
    }

    DTIPointListType pointlist = dynamic_cast<DTITubeType*>((*it).GetPointer())->GetPoints();
    DTITubeType::Pointer newtube = DTITubeType::New();
    DTIPointListType newpoints;

    DTIPointListType::iterator pit;

    // For each point alogng thje fiber
    for(pit = pointlist.begin(); pit != pointlist.end(); ++pit)
    {
      DTIPointType newpoint;
      typedef DTIPointType::PointType PointType;

      // p is not really a point its a continuous index
      const PointType p = pit->GetPosition();
      itk::Point<double, 3> pt;
      // pt is Point in world coordinates (without any reorientation, i.e. disregarding transform matrix)
      pt[0] = p[0] * spacing[0] + sooffset[0];
      pt[1] = p[1] * spacing[1] + sooffset[1];
      pt[2] = p[2] * spacing[2] + sooffset[2];

      typedef DeformationInterpolateType::ContinuousIndexType ContinuousIndexType;
      ContinuousIndexType ci, origci;
      for(unsigned int i =0; i < 3; i++)
        origci[i] = ci[i] = p[i];

      if (vm.count("tensor-volume"))
      {
	// get index in image
	tensorreader->GetOutput()->TransformPhysicalPointToContinuousIndex(pt, ci);
	for(unsigned int i =0; i < 3; i++)
	  origci[i] = ci[i];
	if(deformationfield)
	{
	  // just for debug
	  //std::cout << "p" << p[0] << "," << p[1] << "," << p[2] << std::endl;
	  //std::cout << "ci" << ci[0] << "," << ci[1] << "," << ci[2] << std::endl;

	  DeformationPixelType warp(definterp->EvaluateAtContinuousIndex(ci).GetDataPointer());

	  // Get Spacing from tensorfile
	  TensorImageType::SpacingType tensorspacing = tensorreader->GetOutput()->GetSpacing();

	  for(unsigned int i =0; i < 3; i++)
	    ci[i] = ci[i] + warp[i] / tensorspacing[i];
	}
      }

      if(vm.count("voxelize"))
      {
        itk::Index<3> ind;
        labelimage->TransformPhysicalPointToContinuousIndex(pt, ci);
        ind[0] = static_cast<long int>(round(ci[0]));
        ind[1] = static_cast<long int>(round(ci[1]));
        ind[2] = static_cast<long int>(round(ci[2]));
        if(!labelimage->GetLargestPossibleRegion().IsInside(ind))
        {
          std::cerr << "Error index: " << ind << " not in image"  << std::endl;
          return EXIT_FAILURE;
        }
        if(vm.count("voxelize-count-fibers"))
          labelimage->SetPixel(ind, labelimage->GetPixel(ind) + 1);
        else
          labelimage->SetPixel(ind, vm["voxel-label"].as<ScalarPixelType>());
      }

      // Should not have to do this
      if(vm.count("no-warp"))
        newpoint.SetPosition(origci);
      else
        newpoint.SetPosition(ci);

      newpoint.SetRadius(.4);
      newpoint.SetRed(0.0);
      newpoint.SetGreen(1.0);
      newpoint.SetBlue(0.0);

      // Attribute tensor data if provided
      if(vm.count("tensor-volume") && vm.count("fiber-output"))
      {
        itk::DiffusionTensor3D<double> tensor(tensorinterp->EvaluateAtContinuousIndex(ci).GetDataPointer());

        // TODO: Change SpatialObject interface to accept DiffusionTensor3D
        float sotensor[6];
        for(unsigned int i = 0; i < 6; ++i)
          sotensor[i] = tensor[i];

        newpoint.SetTensorMatrix(sotensor);

        typedef itk::DiffusionTensor3D<double>::EigenValuesArrayType EigenValuesType;
        EigenValuesType eigenvalues;
        tensor.ComputeEigenValues(eigenvalues);

        newpoint.AddField(itk::DTITubeSpatialObjectPoint<3>::FA, tensor.GetFractionalAnisotropy());
        newpoint.AddField("md", tensor.GetTrace()/3);
        newpoint.AddField("fro", sqrt(tensor[0]*tensor[0] +
                                      2*tensor[1]*tensor[1] +
                                      2*tensor[2]*tensor[2] +
                                      tensor[3]*tensor[3] +
                                      2*tensor[4]*tensor[4] +
                                      tensor[5]*tensor[5]));
        newpoint.AddField("l1", eigenvalues[0]);
        newpoint.AddField("l2", eigenvalues[1]);
        newpoint.AddField("l3", eigenvalues[2]);
      }
      else
      {
        newpoint.SetTensorMatrix(pit->GetTensorMatrix());
      }

      newpoints.push_back(newpoint);
    }

    newtube->SetSpacing(newspacing);
    newtube->SetId(id++);
    newtube->SetPoints(newpoints);
    newgroup->AddSpatialObject(newtube);
  }

  newgroup->ComputeObjectToWorldTransform();

  if(VERBOSE)
    std::cout << "Ending Loop" << std::endl;

  if(VERBOSE && vm.count("fiber-output"))
    std::cout << "Output: " << vm["fiber-output"].as<std::string>() << std::endl;

  if(vm.count("fiber-output"))
    writeFiberFile(vm["fiber-output"].as<std::string>(), newgroup);

  if(vm.count("voxelize"))
  {
    typedef itk::ImageFileWriter<IntImageType> LabelWriter;
    LabelWriter::Pointer writer = LabelWriter::New();
    writer->SetInput(labelimage);
    writer->SetFileName(vm["voxelize"].as<std::string>());
    writer->UseCompressionOn();
    try
    {
      writer->Update();
    }
    catch(itk::ExceptionObject & e)
    {
      std::cerr << e.what() << std::endl;
      return EXIT_FAILURE;
    }
  }

  delete children;
  return EXIT_SUCCESS;
}
<commit_msg>BUG: correct fiber coordinates when tensor mapping and deformation application<commit_after> /*=========================================================================

  Program:   NeuroLib (DTI command line tools)
  Language:  C++
  Date:      $Date: 2009-06-09 14:57:41 $
  Version:   $Revision: 1.7 $
  Author:    Casey Goodlett (gcasey@sci.utah.edu)

  Copyright (c)  Casey Goodlett. All rights reserved.
  See NeuroLibCopyright.txt or http://www.ia.unc.edu/dev/Copyright.htm 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.

=========================================================================*/
// STL includes
#include <string>
#include <iostream>
#include <fstream>

// boost includes
#include <boost/program_options/option.hpp>
#include <boost/program_options/options_description.hpp>
#include <boost/program_options/positional_options.hpp>
#include <boost/program_options/variables_map.hpp>
#include <boost/program_options/parsers.hpp>
#include <boost/program_options/cmdline.hpp>

// ITK includes
#include <itkDiffusionTensor3D.h>
#include <itkImageFileReader.h>
#include <itkImageFileWriter.h>
#include <itkTensorLinearInterpolateImageFunction.h>
#include <itkVectorLinearInterpolateImageFunction.h>
#include <itkVersion.h>

//#include "FiberCalculator.h"
#include "deformationfieldoperations.h"
#include "fiberio.h"
#include "dtitypes.h"

namespace po = boost::program_options;

int main(int argc, char* argv[])
{
  // Read program options/configuration
  po::options_description config("Usage: fiberprocess input-fiber [options]");
  config.add_options()
    ("help,h", "produce this help message")
    ("verbose,v", "produces verbose output")

    ("fiber-output,o", po::value<std::string>(), "Output fiber file.  May be warped or updated with new data depending on other options used.")
    ("h-field,H", po::value<std::string>(), "HField for warp and statistics lookup.  If this option is used tensor-volume must also be specified.")
    ("displacement-field", po::value<std::string>(), "Displacement field for warp and statistics lookup.  If this option is used tensor-volume must also be specified.")
    ("no-warp,n", "Do not warp the geometry of the tensors only obtain the new statistics")
    ("tensor-volume,T", po::value<std::string>(), "Interpolate tensor values from the given field")

    // ******  TODO **********
    ("voxelize,V", po::value<std::string>(),"Voxelize fiber into a label map (the labelmap filename is the argument of -V).  The tensor file must be specified using -T for information about the size, origin, spacing of the image.")
    ("voxelize-count-fibers", "Count number of fibers per-voxel instead of just setting to 1")
    ("voxel-label,l", po::value<ScalarPixelType>()->default_value(1),"Label for voxelized fiber")
    ("fiberRadius,R",po::value<double>(),"set radius of all fibers to this value")

    // Compute 1-D statistics
    // ("mean-statistics,s", po::value<std::string>(), "Write summary statistics to text file")
    // ******  TODO **********
    ;

  po::options_description hidden("Hidden options");
  hidden.add_options()
    ("fiber-file", po::value<std::string>(), "DTI fiber file")
    ;

  po::options_description all;
  all.add(config).add(hidden);

  po::positional_options_description p;
  p.add("fiber-file",1);

  po::variables_map vm;

  try
  {
    po::store(po::command_line_parser(argc, argv).
              options(all).positional(p).run(), vm);
    po::notify(vm);
  }
  catch (const po::error &e)
  {
    std::cout << "Parse error: " << std::endl;
    std::cout << config << std::endl;
    return EXIT_FAILURE;
  }

  // End option reading configuration

  // Display help if asked or program improperly called
  if(vm.count("help") || !vm.count("fiber-file"))
  {
    std::cout << config << std::endl;
    if(vm.count("help"))
    {
      std::cout << "Version $Revision: 1.7 $ "<< std::endl;
      std::cout << ITK_SOURCE_VERSION << std::endl;
      return EXIT_SUCCESS;
    }
    else
    {
      return EXIT_FAILURE;
    }
  }

  const bool VERBOSE = vm.count("verbose");

  // Reader fiber bundle
  GroupType::Pointer group = readFiberFile(vm["fiber-file"].as<std::string>());

  DeformationImageType::Pointer deformationfield(NULL);
  if(vm.count("h-field"))
    deformationfield = readDeformationField(vm["h-field"].as<std::string>(), HField);
  else if(vm.count("displacement-field"))
    deformationfield = readDeformationField(vm["displacement-field"].as<std::string>(), Displacement);
  else
    deformationfield = NULL;

  typedef itk::VectorLinearInterpolateImageFunction<DeformationImageType, double> DeformationInterpolateType;
  DeformationInterpolateType::Pointer definterp(NULL);
  if(deformationfield)
  {
    definterp = DeformationInterpolateType::New();
    definterp->SetInputImage(deformationfield);
  }

  // Setup new fiber bundle group
  GroupType::Pointer newgroup = GroupType::New();
  newgroup->SetId(0);

  ChildrenListType* children = group->GetChildren(0);

  if(VERBOSE)
    std::cout << "Getting spacing" << std::endl;

  // Get Spacing and offset from group
  double spacing[3];
  for(unsigned int i =0; i < 3; i++)
    spacing[i] = (group->GetSpacing())[i];
  newgroup->SetSpacing(spacing);

  itk::Vector<double, 3> sooffset;
  for(unsigned int i = 0; i < 3; i++)
    sooffset[i] = (group->GetObjectToParentTransform()->GetOffset())[i];
  newgroup->GetObjectToParentTransform()->SetOffset(sooffset.GetDataPointer());

  if(VERBOSE)
  {
    std::cout << "Group Spacing: " << spacing[0] << ", " << spacing[1] << ", " << spacing[2] << std::endl;
    std::cout << "Group Offset: " << sooffset[0] << ", " << sooffset[1]  << ", " << sooffset[2] << std::endl;
  }

  // Setup tensor file if available
  typedef itk::ImageFileReader<TensorImageType> TensorImageReader;
  typedef itk::TensorLinearInterpolateImageFunction<TensorImageType, double> TensorInterpolateType;
  TensorImageReader::Pointer tensorreader = NULL;
  TensorInterpolateType::Pointer tensorinterp = NULL;

  if(vm.count("tensor-volume"))
  {
    tensorreader = TensorImageReader::New();
    tensorinterp = TensorInterpolateType::New();

    tensorreader->SetFileName(vm["tensor-volume"].as<std::string>().c_str());
    try
    {
      tensorreader->Update();
      tensorinterp->SetInputImage(tensorreader->GetOutput());
    }
    catch(itk::ExceptionObject exp)
    {
      std::cerr << exp << std::endl;
      return EXIT_FAILURE;
    }
  }

  if(VERBOSE)
    std::cout << "Starting Loop" << std::endl;

  ChildrenListType::iterator it;
  unsigned int id = 1;

  // Need to allocate an image to write into for creating
  // the fiber label map
  IntImageType::Pointer labelimage;
  if(vm.count("voxelize"))
  {
    if(!vm.count("tensor-volume"))
    {
      std::cerr << "Must specify tensor file to copy image metadata for fiber voxelize." << std::endl;
      return EXIT_FAILURE;
    }
    tensorreader->GetOutput();
    labelimage = IntImageType::New();
    labelimage->SetSpacing(tensorreader->GetOutput()->GetSpacing());
    labelimage->SetOrigin(tensorreader->GetOutput()->GetOrigin());
    labelimage->SetDirection(tensorreader->GetOutput()->GetDirection());
    labelimage->SetRegions(tensorreader->GetOutput()->GetLargestPossibleRegion());
    labelimage->Allocate();
    labelimage->FillBuffer(0);
  }

  double newspacing[3];
  for(unsigned int i =0; i < 3; i++)
    newspacing[i] = spacing[i];

  if (vm.count("tensor-volume") || vm.count("voxelize"))
  {
    for(unsigned int i =0; i < 3; i++)
      newspacing[i] = 1;
    // fiber coordinates are newly in mm
  }

  // For each fiber
  for(it = children->begin(); it != children->end(); it++)
  {
    // Get Spacing and offset from fiber
    const double* fiberspacing = (*it).GetPointer()->GetSpacing();
    const itk::Vector<double, 3> fibersooffset = dynamic_cast<DTITubeType*>((*it).GetPointer())->GetObjectToParentTransform()->GetOffset();

    // TODO: mode for selecting which to use
    if ((fiberspacing[0] != spacing[0]) || (fiberspacing[1] != spacing[1]) || (fiberspacing[1] != spacing[1]) ||
	(sooffset[0] != fibersooffset[0]) || (sooffset[1] != fibersooffset[1]) || (sooffset[1] != fibersooffset[1]))
    {
      std::cout << "Fiber and group spacing/offset is not equal using the one from the fiber group." << std::endl;
      if(VERBOSE)
      {
	std::cout << "Fiber Spacing: " << fiberspacing[0] << ", " << fiberspacing[1] << ", " << fiberspacing[2] << std::endl;
	std::cout << "Fiber Offset: " << fibersooffset[0] << ", " << fibersooffset[1]  << ", " << fibersooffset[2] << std::endl;
      }
      for(unsigned int i =0; i < 3; i++)
      {
	spacing[i] = fiberspacing[i];
	sooffset[i] = fibersooffset[i];
      }
      newgroup->SetSpacing(spacing);
      newgroup->GetObjectToParentTransform()->SetOffset(sooffset.GetDataPointer());
    }

    DTIPointListType pointlist = dynamic_cast<DTITubeType*>((*it).GetPointer())->GetPoints();
    DTITubeType::Pointer newtube = DTITubeType::New();
    DTIPointListType newpoints;

    DTIPointListType::iterator pit;

    // For each point alogng the fiber
    for(pit = pointlist.begin(); pit != pointlist.end(); ++pit)
    {
      DTIPointType newpoint;
      typedef DTIPointType::PointType PointType;

      // p is not really a point its a continuous index
      const PointType p = pit->GetPosition();
      itk::Point<double, 3> pt;
      // pt is Point in world coordinates (without any reorientation, i.e. disregarding transform matrix)
      pt[0] = p[0] * spacing[0] + sooffset[0];
      pt[1] = p[1] * spacing[1] + sooffset[1];
      pt[2] = p[2] * spacing[2] + sooffset[2];

      typedef DeformationInterpolateType::ContinuousIndexType ContinuousIndexType;
      ContinuousIndexType ci, origci;
      for(unsigned int i =0; i < 3; i++)
        origci[i] = ci[i] = p[i];

      newpoint.SetPosition(ci);

      if (vm.count("tensor-volume"))
      {
	// get index in image
	tensorreader->GetOutput()->TransformPhysicalPointToContinuousIndex(pt, ci);
	for(unsigned int i =0; i < 3; i++)
	  origci[i] = ci[i];
	if(deformationfield)
	{
	  DeformationPixelType warp(definterp->EvaluateAtContinuousIndex(ci).GetDataPointer());

	  // Get Spacing from tensorfile
	  TensorImageType::SpacingType tensorspacing = tensorreader->GetOutput()->GetSpacing();

	  for(unsigned int i =0; i < 3; i++)
	    ci[i] = ci[i] + warp[i] / tensorspacing[i];

	  if(vm.count("no-warp"))
	    newpoint.SetPosition(origci);
	  else
	    newpoint.SetPosition(ci);

	  double  newFiberSpacing[3];
	  for(unsigned int i =0; i < 3; i++)
	    newFiberSpacing[i] =  tensorspacing[i];

	  newgroup->SetSpacing(newFiberSpacing);
	}
      }

      if(vm.count("voxelize"))
      {
        itk::Index<3> ind;
        labelimage->TransformPhysicalPointToContinuousIndex(pt, ci);
        ind[0] = static_cast<long int>(round(ci[0]));
        ind[1] = static_cast<long int>(round(ci[1]));
        ind[2] = static_cast<long int>(round(ci[2]));
        if(!labelimage->GetLargestPossibleRegion().IsInside(ind))
        {
          std::cerr << "Error index: " << ind << " not in image"  << std::endl;
          return EXIT_FAILURE;
        }
        if(vm.count("voxelize-count-fibers"))
          labelimage->SetPixel(ind, labelimage->GetPixel(ind) + 1);
        else
          labelimage->SetPixel(ind, vm["voxel-label"].as<ScalarPixelType>());
      }
      if (vm.count("fiberRadius"))
      {
	newpoint.SetRadius(vm["fiberRadius"].as<double>());
      }
      else
      {
	newpoint.SetRadius(0.4);
      }
      newpoint.SetRed(0.0);
      newpoint.SetGreen(1.0);
      newpoint.SetBlue(0.0);

      // Attribute tensor data if provided
      if(vm.count("tensor-volume") && vm.count("fiber-output"))
      {
	//std::cout << "ci" << ci[0] << "," << ci[1] << "," << ci[2] << std::endl;
        itk::DiffusionTensor3D<double> tensor(tensorinterp->EvaluateAtContinuousIndex(ci).GetDataPointer());

        // TODO: Change SpatialObject interface to accept DiffusionTensor3D
        float sotensor[6];
        for(unsigned int i = 0; i < 6; ++i)
          sotensor[i] = tensor[i];

        newpoint.SetTensorMatrix(sotensor);

        typedef itk::DiffusionTensor3D<double>::EigenValuesArrayType EigenValuesType;
        EigenValuesType eigenvalues;
        tensor.ComputeEigenValues(eigenvalues);

        newpoint.AddField(itk::DTITubeSpatialObjectPoint<3>::FA, tensor.GetFractionalAnisotropy());
        newpoint.AddField("md", tensor.GetTrace()/3);
        newpoint.AddField("fro", sqrt(tensor[0]*tensor[0] +
                                      2*tensor[1]*tensor[1] +
                                      2*tensor[2]*tensor[2] +
                                      tensor[3]*tensor[3] +
                                      2*tensor[4]*tensor[4] +
                                      tensor[5]*tensor[5]));
        newpoint.AddField("l1", eigenvalues[0]);
        newpoint.AddField("l2", eigenvalues[1]);
        newpoint.AddField("l3", eigenvalues[2]);
      }
      else
      {
        newpoint.SetTensorMatrix(pit->GetTensorMatrix());
      }

      newpoints.push_back(newpoint);
    }

    newtube->SetSpacing(newspacing);
    newtube->SetId(id++);
    newtube->SetPoints(newpoints);
    newgroup->AddSpatialObject(newtube);
  }

  newgroup->ComputeObjectToWorldTransform();

  if(VERBOSE)
    std::cout << "Ending Loop" << std::endl;

  if(VERBOSE && vm.count("fiber-output"))
    std::cout << "Output: " << vm["fiber-output"].as<std::string>() << std::endl;

  if(vm.count("fiber-output"))
    writeFiberFile(vm["fiber-output"].as<std::string>(), newgroup);

  if(vm.count("voxelize"))
  {
    typedef itk::ImageFileWriter<IntImageType> LabelWriter;
    LabelWriter::Pointer writer = LabelWriter::New();
    writer->SetInput(labelimage);
    writer->SetFileName(vm["voxelize"].as<std::string>());
    writer->UseCompressionOn();
    try
    {
      writer->Update();
    }
    catch(itk::ExceptionObject & e)
    {
      std::cerr << e.what() << std::endl;
      return EXIT_FAILURE;
    }
  }

  delete children;
  return EXIT_SUCCESS;
}
<|endoftext|>