/*
 * Copyright (C) 2007 askywhale
 *
 *  This program is free software; you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License (version 2)
 *  as published by the Free Software Foundation.
 *
 *  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.
 *
 */

package com.askywhale.rings;

import net.sf.j3d.util.graphics.RGB;
import net.sf.j3d.util.Vector;


/**
 * Rings Raytracer related class
 * 
 * Propose some simple 3d surfaces (change kind attribute)
 * 
 * @author askywhale
 *
 */
public class SimpleSymetricIsoSurface extends IsoSurface {
    
	public static final int SPHERE = 0;
	public static final int OCTAEDRON = 1;
	public static final int STAR_6 = 2;
	public static final int SLICED_SPHERE = 3;
	public static final int DBL_CONE = 4;
	public static final int CYLINDER = 5;
	public static final int VIS = 6;
	public static final int STAR_6_BIS = 7;
	public static final int CROSS = 8;
	public static final int GOO_SPHERE = 9;
	public static final int MOEBIUS = 10;
	
	private int kind;
	private double specialValue;
	
    public SimpleSymetricIsoSurface(Vector location, double size, RGB color, int kind) {
        super(location, size, color);
        this.kind = kind;
        specialValue = 1;
    }

    protected double getValue(Vector point) {
    	double x = point.getX(), y = point.getY(), z = point.getZ();
    	switch(kind) {
    	case OCTAEDRON:
    		return        
            Math.abs(x)+
            Math.abs(point.getY())+
            Math.abs(point.getZ())-1;
    	case STAR_6:
    		return        
            Math.abs(x*point.getY())+
            Math.abs(point.getY()*point.getZ())+
            Math.abs(point.getZ()*x)-.33;
    	case STAR_6_BIS:
    		return Math.min(Math.min(
    				Math.abs(x)+Math.abs(point.getY()),
    				Math.abs(x)+Math.abs(point.getZ())),
    				Math.abs(point.getY())+Math.abs(point.getZ()))+
    				specialValue*(Math.abs(x)+
    				Math.abs(point.getY())+
    				Math.abs(point.getZ()))-
    				1;
    	case SLICED_SPHERE:
    		if(Math.floor(x*8*specialValue)%2==0)
    			return 1;
    		else       
    			return point.length()-1;
    	case DBL_CONE:
    		return Math.hypot(x,point.getY())+
    			Math.abs(point.getZ())-1.0;
    	case CYLINDER:
    		return Math.hypot(x,point.getY())+
    			Math.floor(2*Math.abs(point.getZ())-1.0);
    	case VIS:
    		return Math.hypot(x,point.getY())*2*
    		(2+Math.sin(point.getZ()*16*specialValue+Math.atan2(point.getY(),x)))+
    			Math.floor(2*Math.abs(point.getZ())-1.0);
    	case CROSS:
    		return Math.max(8*Math.min(Math.min(
    				Math.max(Math.abs(x),Math.abs(point.getY())),
    				Math.max(Math.abs(x),Math.abs(point.getZ()))),
    				Math.max(Math.abs(point.getY()),Math.abs(point.getZ()))),
    				Math.max(Math.max(Math.abs(x),
    				Math.abs(point.getY())),
    				Math.abs(point.getZ())))-1;
    	case GOO_SPHERE:
    		return point.length()-1-.03*specialValue*
    			(Math.cos(x*7)+Math.sin(y*9)+Math.cos(z*11)+
    					Math.cos(x*23)+Math.sin(y*19)+Math.cos(z*17));
    	case MOEBIUS:
    		double xx = Math.hypot(x,y)-1;
    		double yy = z;
    		double a = Math.atan2(y,x)*.5;
    		double optCosA = Math.cos(a);
    		double optSinA = Math.sin(a);
    		double rx = Math.abs(optCosA*xx+optSinA*yy)*50;
    		double ry = Math.abs(optCosA*yy-optSinA*xx)*3*specialValue;
    		return Math.max(rx,ry)-1;
    	default:
    		/*if(point.length()<1)
    			return -1;
    		else
    			return 1;
    		*/return point.length()-1;
    	}  	
    }

	public int getKind() {
		return kind;
	}

	public void setKind(int kind) {
		this.kind = kind;
	}

	public double getSpecialValue() {
		return specialValue;
	}

	/**
	 * 
	 * @param specialValue value that default to 1 and is used by
	 * the surface in a way or another
	 */
	public void setSpecialValue(double specialValue) {
		this.specialValue = specialValue;
	}    
}
