JVector
JXMesaCamera::ScreenToModel
	(
	const JVector& pt
	)
{
	if (!PrepareMesa())
		{
		return pt;
		}

	PrepareTransforms();

	GLdouble modelMatrix[16], projMatrix[16];
	GLint viewport[4];

	glGetDoublev(GL_MODELVIEW_MATRIX, modelMatrix);
	glGetDoublev(GL_PROJECTION_MATRIX, projMatrix);
	glGetIntegerv(GL_VIEWPORT, viewport);

	JFloat x,y,z;
	gluUnProject(pt.GetElement(1), pt.GetElement(2), pt.GetElement(3),
				 modelMatrix, projMatrix, viewport, &x, &y, &z);

	return JVector(3, x, y, z);
}
void
JX3DWidget::ContinueDrag
	(
	const JPoint& pt
	)
{
	if (itsDragType == kRotateDrag)
		{
		const JVector delta(3, - pt.x + itsStartPt.x, pt.y - itsStartPt.y, 0.0);

		const JVector& o = itsCamera->GetAttentionPt();
		JVector v        = itsStartPos - o;
		const JFloat r   = v.GetLength();
		const JFloat lat = asin(v.GetElement(3) / r);
		const JFloat lon = atan2(v.GetElement(2), v.GetElement(1));

		// direction of drag relative to screen x-axis

		const JFloat alpha = atan2(delta.GetElement(2), delta.GetElement(1));

		// delta along the sphere in drag direction

		const JFloat phi = delta.GetLength() / (r * 50);
		JVector p(3, r*cos(phi), r*sin(phi), 0.0);

		// inverse: rotate around z-axis for partial alignment of x-axis

		JMatrix r1(3, 3);
		r1.SetElements(
			cos(lon), -sin(lon), 0.0,
			sin(lon),  cos(lon), 0.0,
				 0.0,       0.0, 1.0);

		// inverse: rotate around y-axis for complete alignment of x-axis towards viewer

		JMatrix r2(3, 3);
		r2.SetElements(
			cos(lat), 0.0, -sin(lat),
				 0.0, 1.0,       0.0,
			sin(lat), 0.0,  cos(lat));

		// inverse: rotate around x-axis to align y-axis with drag direction

		JMatrix r3(3, 3);
		r3.SetElements(
			1.0,        0.0,         0.0,
			0.0, cos(alpha), -sin(alpha),
			0.0, sin(alpha),  cos(alpha));

		// transform delta long the sphere to our coordinate system

		p = (r1 * r2 * r3 * p).GetColVector(1);

		itsCamera->SetPosition(p + o);
		}
}
void
JPlotFitQuad2::SetErrors
	(
	const JVector& p
	)
{
	itsAErrParameter	= p.GetElement(1);
	itsBErrParameter	= p.GetElement(2);
	itsCErrParameter	= p.GetElement(3);
}
void
JPlotFitQuad2::SetCurrentParameters
	(
	const JVector& p
	)
{
	itsAParameter	= p.GetElement(1);
	itsBParameter	= p.GetElement(2);
	itsCParameter	= p.GetElement(3);
}
void
JPlotFitExp::SetErrors
	(
	const JVector& p
	)
{
	itsAErr	= p.GetElement(1);
	itsBErr	= p.GetElement(2);
}
void
JPlotFitExp::SetCurrentParameters
	(
	const JVector& p
	)
{
	itsAParm	= p.GetElement(1);
	itsBParm	= p.GetElement(2);
}
JVector
TanhLinNetwork::g
	(
	const JIndex	layerIndex,
	const JVector&	h
	)
	const
{
	const JSize dimCount = h.GetDimensionCount();

	JVector result(dimCount);

	for (JIndex i=1;i<=dimCount;i++)
		{
		const JFloat value = h.GetElement(i);
		result.SetElement(i, g(layerIndex, value));
		}

	return result;
}
JBoolean
JX3DWidget::HandleRotationKeyPress
	(
	const int				key,
	const JXKeyModifiers&	modifiers
	)
{
	if (modifiers.meta() && key == kJUpArrow)
		{
		return ZoomForWheel(kJXButton4, modifiers);
		}
	else if (modifiers.meta() && key == kJDownArrow)
		{
		return ZoomForWheel(kJXButton5, modifiers);
		}

	const JVector& o = itsCamera->GetAttentionPt();
	JVector v        = itsCamera->GetPosition() - o;
	const JFloat r   = v.GetLength();
	JFloat lat       = asin(v.GetElement(3) / r);
	JFloat lon       = atan2(v.GetElement(2), v.GetElement(1));

	const JFloat delta =
		(modifiers.shift()   ? kSmallDeltaAngle :
		(modifiers.control() ? kBigDeltaAngle   :
		kDeltaAngle));

	JBoolean moved = kJFalse;

	if (key == kJUpArrow)
		{
		lat  += delta;
		moved = kJTrue;
		}
	else if (key == kJDownArrow)
		{
		lat  -= delta;
		moved = kJTrue;
		}

	else if (key == kJLeftArrow)
		{
		lon  += delta;
		moved = kJTrue;
		}
	else if (key == kJRightArrow)
		{
		lon  -= delta;
		moved = kJTrue;
		}

	if (moved)
		{
		itsCamera->SetPosition(JVector(3,
			r * cos(lat) * cos(lon),
			r * cos(lat) * sin(lon),
			r * sin(lat)));

		Redraw();	// key repeats can delay Refresh()
		return kJTrue;
		}
	else
		{
		return kJFalse;
		}
}