#include "StdAfx.h"
#include "CrossSectionConfig.h"



CrossSectionConfig::CrossSectionConfig(void)
{
	m_Enable = false;
	m_CutPosX = 0.5f;
	m_CutPosY = 0.5f;
	m_CutPosZ = 0.5f;

	m_Ribbon      = false;
	m_RibbonRange = 0.02f;

	m_LineCS = false;
	m_MultiColor = false;

	m_ShowCutplane = false;

	m_EnableConvexHull        = false;
	m_EnableShowLength        = false;
	m_EnableShowCHLength      = false;
	m_EnableCrossSectionGroup = true;

	m_Transparent = false;

	m_CutAngle = CutAngle::CUT_Y_FORE;
}

void CrossSectionConfig::GetCutPlane(const lm::range3f& tb, lib_geo::Plane& cutplane) const
{
	const lm::vec3f& vt = tb.max_point();
	const lm::vec3f& vb = tb.min_point();
	float np = GetCurrentAxisCutPos();

	cutplane.normal = GetCutAxis();
	cutplane.origin = vb + (vt - vb) * np;
}

void CrossSectionConfig::ApplyCutPlaneAxis(bool forCut, const lm::range3f bbox)
{
	lm::vec3f vt = bbox.max_point();
	lm::vec3f vb = bbox.min_point();

	lm::vec3f ax = GetCutAxis();
	ClipRange cr;
	cr.t = dot(vt, ax);
	cr.b = dot(vb, ax);

	ApplyCutPlaneAxis(forCut, cr);
}

lm::vec3f CrossSectionConfig::GetCutAxis(void) const
{
	switch (GetCurrentCutAxis())
	{
	case AxisType::X : return lm::vec3f(1, 0, 0);
	case AxisType::Y : return lm::vec3f(0, 1, 0);
	case AxisType::Z : return lm::vec3f(0, 0, 1);
	default:
		assert(false);
		return lm::vec3f();
	}
}

void CrossSectionConfig::ApplyCutPlaneAxis(bool forCut, const ClipRange& cr)
{
	float np = GetCurrentAxisCutPos();
	GLdouble h = (GLdouble)(cr.b + cr.GetWidth() * np);

	AxisType ax = GetCurrentCutAxis();
	if (forCut)
	{
		SetAxisClipPlane(ax, GL_CLIP_PLANE0, true, h);
		SetAxisClipPlane(ax, GL_CLIP_PLANE1, false, h);
	}
	else
	{
		bool fore = !IsCutRev();
		if (m_Ribbon)
		{
			GLdouble rr = (GLdouble)(cr.GetWidth() * 0.5 * m_RibbonRange);
			if (IsCutRev())
				rr *= -1.0f;

			SetAxisClipPlane(ax, GL_CLIP_PLANE0,  fore, h + rr);
			SetAxisClipPlane(ax, GL_CLIP_PLANE1, !fore, h - rr);
		}
		else
		{
			SetAxisClipPlane(ax,GL_CLIP_PLANE0, fore, h);
		}
	}
}

void CrossSectionConfig::ApplyCutPlane(bool forCut, const lm::range3f& bbox, const lm::vec3f& p, const lm::vec3f& n)
{
	lm::vec3f rn = n;
	if (IsCutRev())
		rn = -rn;

	float drn = dot(p, rn);

	if (forCut)
	{
		SetGLClipPlane(GL_CLIP_PLANE0, rn, -drn);
		SetGLClipPlane(GL_CLIP_PLANE1, -rn, drn);
	}
	else
	{
		if (m_Ribbon)
		{
			const lm::vec3f& t = bbox.min_point();
			const lm::vec3f& b = bbox.max_point();
			lm::vec3f d = t - b;

			GLdouble rr = (GLdouble)(d.length() * 0.5 * m_RibbonRange);

			SetGLClipPlane(GL_CLIP_PLANE0,  rn, -(drn - rr));
			SetGLClipPlane(GL_CLIP_PLANE1, -rn,  (drn + rr));
		}
		else
		{
			SetGLClipPlane(GL_CLIP_PLANE0, rn, -drn);
		}
	}
}

void CrossSectionConfig::DisableGLClipPlane(void)
{
	glDisable(GL_CLIP_PLANE0);
	glDisable(GL_CLIP_PLANE1);
	glDisable(GL_CLIP_PLANE2);
	glDisable(GL_CLIP_PLANE3);
	glDisable(GL_CLIP_PLANE4);
	glDisable(GL_CLIP_PLANE5);
}

bool CrossSectionConfig::IsCutX(void) const
{
	return GetCurrentCutAxis() == AxisType::X;
}

bool CrossSectionConfig::IsCutY(void) const
{
	return GetCurrentCutAxis() == AxisType::Y;
}

bool CrossSectionConfig::IsCutZ(void) const
{
	return GetCurrentCutAxis() == AxisType::Z;
}

AxisType CrossSectionConfig::GetCurrentCutAxis(void) const
{
	switch (m_CutAngle)
	{
	case CutAngle::CUT_X_FORE :
	case CutAngle::CUT_X_REV  : return AxisType::X;
	case CutAngle::CUT_Y_FORE :
	case CutAngle::CUT_Y_REV  : return AxisType::Y;
	case CutAngle::CUT_Z_FORE :
	case CutAngle::CUT_Z_REV  : return AxisType::Z;
	default:
		return AxisType::None;
	}
}

float CrossSectionConfig::GetCurrentAxisCutPos(void) const
{
	switch (GetCurrentCutAxis())
	{
	case AxisType::X : return m_CutPosX;
	case AxisType::Y : return m_CutPosY;
	case AxisType::Z : return m_CutPosZ;
	default:
		assert(false);
		return 0.0f;
	}
}

void CrossSectionConfig::SetAxisClipPlane(AxisType axis, GLenum plane, bool fore, GLdouble height)
{
	switch (axis)
	{
	case AxisType::X : return SetAxisClipPlaneX(plane, fore, height);
	case AxisType::Y : return SetAxisClipPlaneY(plane, fore, height);
	case AxisType::Z : return SetAxisClipPlaneZ(plane, fore, height);
	default:
		assert(false);
		break;
	}
}

void CrossSectionConfig::SetAxisClipPlaneX(GLenum plane, bool fore, GLdouble height)
{
	glEnable(plane);
	glClipPlaneFuncX(plane, fore, height);
}

void CrossSectionConfig::SetAxisClipPlaneY(GLenum plane, bool fore, GLdouble height)
{
	glEnable(plane);
	glClipPlaneFuncY(plane, fore, height);
}

void CrossSectionConfig::SetAxisClipPlaneZ(GLenum plane, bool fore, GLdouble height)
{
	glEnable(plane);
	glClipPlaneFuncZ(plane, fore, height);
}

void CrossSectionConfig::SetGLClipPlane(GLenum plane, const lm::vec3f& n, GLdouble height)
{
	glEnable(plane);
	glClipPlaneFunc(plane, n.x, n.y, n.z, height);
}

bool CrossSectionConfig::IsCutRev(void) const
{
	switch(m_CutAngle)
	{
	case CutAngle::CUT_X_REV:
	case CutAngle::CUT_Y_REV:
	case CutAngle::CUT_Z_REV:
		return true;
	default:
		return false;
	}
}

void CrossSectionConfig::SetAxisCut(AxisType axis, bool fore)
{
	if (axis == AxisType::X)
		m_CutAngle = fore ? CutAngle::CUT_X_FORE : CutAngle::CUT_X_REV;
	else if (axis == AxisType::Y)
		m_CutAngle = fore ? CutAngle::CUT_Y_FORE : CutAngle::CUT_Y_REV;
	else if (axis == AxisType::Z)
		m_CutAngle = fore ? CutAngle::CUT_Z_FORE : CutAngle::CUT_Z_REV;
}

bool CrossSectionConfig::IsFreeCut(void) const
{
	return (m_CutAngle == CutAngle::CUT_FREE);
}

void CrossSectionConfig::SetFreeCut(void)
{
	m_CutAngle = CutAngle::CUT_FREE;
}

bool CrossSectionConfig::IsRequireUpdateCS(void) const
{
	if (m_EnableShowLength)
		return true;

	if (m_EnableShowCHLength)
		return true;

	if (m_EnableConvexHull)
		return true;

	return false;
}
