package vgp.tutor.transform;

import jv.geom.PgPolygonSet;
import jv.loader.PgLoader;
import jv.number.PuDouble;
import jv.object.PsConfig;
import jv.object.PsDebug;
import jv.project.PgGeometry;
import jv.project.PgGeometryIf;
import jv.project.PjProject;
import jv.vecmath.PdMatrix;
import jv.vecmath.PdVector;

/**
 * Demo project to use transformations in ambient space forms.
 * 
 * @author		Konrad Polthier
 * @version		09.06.06, 1.20 revised (kp) Reset improved, now geometry is reset too.<br>
 *					21.10.00, 1.10 revised (kp) Move loading of geometry into start() method from init().<br>
 *					25.12.99, 1.00 created (kp)
 */
public class PjTransform extends PjProject {
	/** Saved initial surface. */
	protected	PgPolygonSet		m_surfaceSave;
	/** Shown surface in 4D space. */
	protected	PgPolygonSet		m_surface;
	/** Rotation around xw axis. */
	protected	PuDouble				m_angleXW;
	/** Rotation around yw axis. */
	protected	PuDouble				m_angleYW;
	/** Rotation around zw axis. */
	protected	PuDouble				m_angleZW;
	/** Transformation matrix in space form. */
	protected	PdMatrix				m_modelMat;
	/** Save previous values of angle. */
	protected	double				m_angleXWPrev;
	/** Save previous values of angle. */
	protected	double				m_angleYWPrev;
	/** Save previous values of angle. */
	protected	double				m_angleZWPrev;

	public PjTransform() {
		super("Transform");
		m_angleXW		= new PuDouble("angleXW", this);
		m_angleYW		= new PuDouble("angleYW", this);
		m_angleZW		= new PuDouble("angleZW", this);
		m_modelMat		= new PdMatrix(4);
		if (getClass() == PjTransform.class)
		  init();
	}
	public void init() {
		super.init();
		m_angleXW.setDefBounds(-Math.PI, Math.PI, 0.01, 0.1);
		m_angleXW.setDefValue(0.);
		m_angleXW.init();
		m_angleXWPrev = 0.;
		m_angleYW.setDefBounds(-Math.PI, Math.PI, 0.01, 0.1);
		m_angleYW.setDefValue(0.);
		m_angleYW.init();
		m_angleYWPrev = 0.;
		m_angleZW.setDefBounds(-Math.PI, Math.PI, 0.01, 0.1);
		m_angleZW.setDefValue(0.);
		m_angleZW.init();
		m_angleZWPrev = 0.;
		
		if (m_surfaceSave!=null && m_surface!=null) {
			m_surface.copy(m_surfaceSave);
		}
	}
	public void start() {
		if (PsDebug.NOTIFY) PsDebug.notify("PjTransform.start: ");
		PgLoader loader = new PgLoader();
		PgGeometry [] geomArr = loader.loadGeometry(new PgGeometry[] {m_surface},
																  PsConfig.getCodeBase()+"models/polytope/Cube4d.jvx");
		if (geomArr==null || geomArr.length==0 || geomArr[0]==null) {
			if (PsDebug.WARNING) PsDebug.warning("loading failed.");
			return;
		}
		m_surface = (PgPolygonSet)geomArr[0];
															 
		m_surface.setName("Exhibited Surface");
		m_surface.projectToSphere(new PdVector(4), 1.);
		m_surface.setAmbientSpace(PgGeometryIf.AMBIENT_S3_SPHERE);
		m_surface.setAmbientProjection(PgGeometryIf.PROJ_STEREOGRAPHIC);
		
		m_surfaceSave = (PgPolygonSet)m_surface.clone();

		addGeometry(m_surface);
		selectGeometry(m_surface);

		m_surface.update(m_surface);

		super.start();
	}

	/**
	 * Update the class whenever a child has changed.
	 * Method is usually invoked from the children.
	 */
	public boolean update(Object event) {
		if (PsDebug.NOTIFY) PsDebug.notify("PjTransform.update() called");
		if (event == m_angleXW) {
			double angleXW = m_angleXW.getValue() - m_angleXWPrev;
			m_angleXWPrev = m_angleXW.getValue();
			rotateXW(angleXW);
			m_surface.update(m_surface);
			return true;
		} else if (event == m_angleYW) {
			double angleYW = m_angleYW.getValue() - m_angleYWPrev;
			m_angleYWPrev = m_angleYW.getValue();
			rotateYW(angleYW);
			m_surface.update(m_surface);
			return true;
		} else if (event == m_angleZW) {
			double angleZW = m_angleZW.getValue() - m_angleZWPrev;
			m_angleZWPrev = m_angleZW.getValue();
			rotateZW(angleZW);
			m_surface.update(m_surface);
			return true;
		}
		return false;
	}
	public void rotateXW(double angleXW) {
		m_modelMat.setIdentity();
		m_modelMat.m_data[0][0]		= Math.cos(angleXW);
		m_modelMat.m_data[0][3]		=-Math.sin(angleXW);
		m_modelMat.m_data[3][0]		= Math.sin(angleXW);
		m_modelMat.m_data[3][3]		= Math.cos(angleXW);
		
		PdVector [] vertex = m_surface.getVertices();
		for (int i=0; i<vertex.length; i++) {
			vertex[i].leftMultMatrix(m_modelMat);
		}
	}
	public void rotateYW(double angleYW) {
		m_modelMat.setIdentity();
		m_modelMat.m_data[1][1]		= Math.cos(angleYW);
		m_modelMat.m_data[1][3]		=-Math.sin(angleYW);
		m_modelMat.m_data[3][1]		= Math.sin(angleYW);
		m_modelMat.m_data[3][3]		= Math.cos(angleYW);
		
		PdVector [] vertex = m_surface.getVertices();
		for (int i=0; i<vertex.length; i++) {
			vertex[i].leftMultMatrix(m_modelMat);
		}
	}
	public void rotateZW(double angleZW) {
		m_modelMat.setIdentity();
		m_modelMat.m_data[2][2]		= Math.cos(angleZW);
		m_modelMat.m_data[2][3]		=-Math.sin(angleZW);
		m_modelMat.m_data[3][2]		= Math.sin(angleZW);
		m_modelMat.m_data[3][3]		= Math.cos(angleZW);
		
		PdVector [] vertex = m_surface.getVertices();
		for (int i=0; i<vertex.length; i++) {
			vertex[i].leftMultMatrix(m_modelMat);
		}
	}
}

