/*
!=======================================================================
!
!  PROGRAM  PHASE-Viewer  (PHASE-Viewer 2014.01 ver.3.3.0)
!
!  Created on 2006/06/27, 21:19
!  AUTHOR(S): KOGA, Junichiro
!  File : Isosurface.java
!  
!  Contact address :  Phase System Consortium
!                     E-mail: phase_system@nims.go.jp URL https://azuma.nims.go.jp
!
!
!   Since 2002, this program set had been intensively developed as a part of the following 
!  national projects supported by the Ministry of Education, Culture, Sports, Science and
!  Technology (MEXT) of Japan; "Frontier Simulation Software for Industrial Science
!  (FSIS)" from 2002 to 2005, "Revolutionary Simulation Software (RSS21)" from 2006 to
!  2008. "Research and Development of Innovative Simulation Software (RISS)" from 2008
!  to 2013. These projects is lead by the Center for Research on Innovative Simulation 
!  Software (CISS), the Institute of Industrial Science (IIS), the University of Tokyo.
!   Since 2013, this program set has been further developed centering on PHASE System
!  Consortium. 
!   The activity of development of this program set has been supervised by Takahisa Ohno.
!
!=======================================================================
 */

package ciss.phase_viewer.acviewer.scenegraphelements;

import java.util.Vector;

import javax.media.j3d.Appearance;
import javax.media.j3d.BranchGroup;
import javax.media.j3d.ColoringAttributes;
import javax.media.j3d.GeometryArray;
import javax.media.j3d.Material;
import javax.media.j3d.PolygonAttributes;
import javax.media.j3d.Shape3D;
import javax.media.j3d.TransformGroup;
import javax.media.j3d.TransparencyAttributes;
import javax.vecmath.Color3f;
import javax.vecmath.Point3f;
import javax.vecmath.Vector3f;

import org.apache.log4j.Logger;

import ciss.phase_viewer.acviewer.ConfigData;
import ciss.phase_viewer.acviewer.ConfigDataUpdateEvent;
import ciss.phase_viewer.acviewer.CoordsViewerInterface;
import ciss.phase_viewer.acviewer.J3DPanel;
import ciss.phase_viewer.acviewer.MainPanel;
import ciss.phase_viewer.acviewer.geom.Plane;
import ciss.phase_viewer.acviewer.scenegraphelements.abinitmp.MarchingCube;
import ciss.phase_viewer.atomcoord.VolumetricData;
import ciss.phase_viewer.settings.GlobalProperties;
import ciss.phase_viewer.settings.PropertiesManager;

import com.sun.j3d.utils.geometry.GeometryInfo;
import com.sun.j3d.utils.geometry.NormalGenerator;
import com.sun.j3d.utils.geometry.Stripifier;

/**
 * 「等値面」オブジェクト.
 * 
 * @author
 */
public class Isosurface extends BranchGroup implements ConfigData {
    private Logger logger = Logger.getLogger(Isosurface.class.getName());

    protected static int MC = 0;

    protected static int GINFO = 1;

    private int normalGenerator = MC;

    private int normalGenerator_buff = -1;

    private Color3f color = new Color3f(0.9f, 0.9f, 0.5f);

    private Color3f color_buff;

    private J3DPanel parentPanel;

    private VolumetricData chargeDensity;

    private float value;

    private float value_buff;

    private float transparency = 0.f;

    private float transparency_buff = 0.f;

    private int ID;

    private GlobalProperties gp = PropertiesManager
            .getGlobalProperties(PropertiesManager.PROPERTIES_ACV);

    private Plane[] planes;

    private boolean firstQuadrantOnly = false;

    private float[][] axisVector;

    /**
     * 等値面の値, 色などが設定可能パラメター.
     * 
     * @param parentPanel
     *            親パネル
     * @param chargeDensity
     *            電荷密度オブジェクト
     * @param color
     *            等値面の色
     * @param value
     *            等値面の値
     * @param ID
     *            識別用のID
     */
    public Isosurface(J3DPanel mainPanel, VolumetricData chargeDensity,
            Color3f color, float value, float transparency, int ID) {
        this.parentPanel = mainPanel;
        this.chargeDensity = chargeDensity;
        this.color = color;
        this.value = value;
        if (transparency >= 0 && transparency <= 1) {
            this.transparency = transparency;
        }
        this.ID = ID;
        init();
    }

    private int cID;

    public void setChargeID(int cID) {
        this.cID = cID;
    }

    public int getChargeID() {
        return cID;
    }

    /**
     * 与えられたデータが"第一象限"のそれだった場合, 他象限まで広げるためのプロパティーを設定する.
     * 
     * @param firstQuadrantOnly
     *            これがtrueの時他象限まで広げる
     * @param axisVector
     *            軸を定義するベクトル; 必ずしも直交座標系である必要はない.
     */
    public void setFirstQuadrantOnly(boolean firstQuadrantOnly,
            float[][] axisVector) {
        this.firstQuadrantOnly = firstQuadrantOnly;
        this.axisVector = axisVector;
    }

    /**
     * clipする面を登録する.
     * 
     * @param planes
     *            clipしたい面の配列
     */
    public void setClippingPlane(Plane[] planes) {
        this.planes = planes;
    }

    /**
     * 「法線ベクトルの作成方法」をセット
     * 
     * @param 法線ベクトルの作成方法
     *            ; MCの場合MarchingCube法によって得られるベクトルを採用.
     *            GINFOの場合はGeometryInfoを利用して作成. 大体の場合MCの方がキレイな出力となるが,
     *            VRML出力ではGINFOの方がよい結果が得られる.
     */
    public void setNormalGenerator(int normalGenerator) {
        this.normalGenerator = normalGenerator;
    }

    /**
     * 法線ベクトルの作成方法を取得.
     * 
     * @return 法線ベクトルの作成方法
     */
    public int getNormalGenerator() {
        return this.normalGenerator;
    }

    /**
     * 等値面の色をセット.
     * 
     * @param color
     *            任意の色
     */
    public void setColor(Color3f color) {
        this.color = color;
    }

    /**
     * 等値面の色を取得.
     * 
     * @return 等値面の色
     */
    public Color3f getColor() {
        return this.color;
    }

    /**
     * 等値面の値
     * 
     * @param value
     *            任意の値
     */
    public void setValue(float value) {
        this.value = value;
    }

    private boolean initinit = true;

    /**
     * 密度をセットしなおす
     * 
     * @param density
     *            セットし直すべき電荷データ
     */
    public void setChargeDensity(VolumetricData chargeDensity) {
        this.chargeDensity = chargeDensity;
        initinit = false;
        init();
        forceCreation = true;
    }

    /**
     * 再描画可能な状態にする.
     */
    public void reset() {
        initinit = false;
        init();
        forceCreation = true;
    }

    /**
     * 透明度の設定 0から1の間の数を指定しない場合は何も起こらない.
     * 
     * @param transparency
     *            透明度
     */
    public void setTransparency(float transparency) {
        if (transparency >= 0 && transparency <= 1) {
            this.transparency = transparency;
            this.transparency_buff = transparency;
        }
    }

    /**
     * 透明度を取得
     * 
     * @return 透明度
     */
    public float getTransparency() {
        return this.transparency;
    }

    /**
     * 等値面の値を取得.
     * 
     * @return 等値面の値
     */
    public float getValue() {
        return this.value;
    }

    /**
     * IDをセットし直す.
     */
    public void setID(int ID) {
        this.ID = ID;
    }

    private float[] densityValue;

    private float[][] coordinates;

    private int[] ndiv;

    private MarchingCube mc;

    private Vector coordData;

    private Vector normal;

    private TGAtom tgatom;

    private Shape3D shape3D;

    private Appearance appearance;

    private PolygonAttributes polygonAttributes;

    private ColoringAttributes coloringAttributes;

    private TransparencyAttributes transparencyAttributes;

    private void init() {
        setCapability(BranchGroup.ALLOW_DETACH);

        densityValue = chargeDensity.getDensity();
        ndiv = chargeDensity.getNumDiv();
        coordData = new Vector();
        normal = new Vector();
        mc = new MarchingCube();

        if (initinit) {
            shape3D = new Shape3D();
            shape3D.setCapability(Shape3D.ALLOW_APPEARANCE_WRITE);
            shape3D.setCapability(Shape3D.ALLOW_GEOMETRY_WRITE);

            appearance = new Appearance();
            appearance.setCapability(Appearance.ALLOW_MATERIAL_WRITE);
            appearance.setCapability(Appearance.ALLOW_POLYGON_ATTRIBUTES_WRITE);
            appearance
                    .setCapability(Appearance.ALLOW_COLORING_ATTRIBUTES_WRITE);
            appearance
                    .setCapability(Appearance.ALLOW_TRANSPARENCY_ATTRIBUTES_WRITE);
            appearance
                    .setCapability(Appearance.ALLOW_TRANSPARENCY_ATTRIBUTES_READ);
            shape3D.setAppearance(appearance);

            polygonAttributes = new PolygonAttributes();
            polygonAttributes
                    .setCapability(PolygonAttributes.ALLOW_CULL_FACE_WRITE);

            coloringAttributes = new ColoringAttributes();
            coloringAttributes
                    .setCapability(ColoringAttributes.ALLOW_SHADE_MODEL_WRITE);

            transparencyAttributes = new TransparencyAttributes();
            transparencyAttributes
                    .setCapability(TransparencyAttributes.ALLOW_VALUE_WRITE);
            transparencyAttributes
                    .setCapability(TransparencyAttributes.ALLOW_VALUE_READ);
            transparencyAttributes
                    .setCapability(TransparencyAttributes.ALLOW_MODE_WRITE);
            if (transparency == 0) {
                transparencyAttributes
                        .setTransparencyMode(TransparencyAttributes.SCREEN_DOOR);
            } else {
                transparencyAttributes
                        .setTransparencyMode(TransparencyAttributes.BLENDED);
            }
            transparencyAttributes.setTransparency(transparency);
            appearance.setTransparencyAttributes(transparencyAttributes);
            addChild(shape3D);

            if (parentPanel instanceof MainPanel) {
                ((CoordsViewerInterface) parentPanel).getCD().register(this);
            }
        }
    }

    private boolean forceCreation = false;

    /**
     * 値が変更されていない場合等値面を再構築することはしないが, ここでtrueをセットしておくと いかなる場合も等値面は再構築される.
     * 
     * @param forceCreation
     *            trueならいつでも等値面が作成される.
     */
    public void forceCreation(boolean forceCreation) {
        this.forceCreation = forceCreation;
    }

    /**
     * セット済みの値を利用して等値面を作成.
     */
    public void createIsoSurface() {
        TransformGroup tgatom = null;
        if (parentPanel instanceof MainPanel) {
            tgatom = ((CoordsViewerInterface) parentPanel).getScene()
                    .getTGAtom();
        }

        Material material = new Material();
        material.setDiffuseColor(color);
        material.setShininess(128f);
        appearance.setMaterial(material);

        /* なぜか以下のコードを入れると表示がおかしくなる. */
        // if ( transparency == 0 ) {
        // transparencyAttributes.setTransparencyMode(TransparencyAttributes.NONE);
        // } else {
        // transparencyAttributes.setTransparencyMode(TransparencyAttributes.BLENDED);
        // }
        // transparencyAttributes.setTransparency(transparency);
        //
        transparencyAttributes = new TransparencyAttributes();
        transparencyAttributes
                .setCapability(TransparencyAttributes.ALLOW_VALUE_WRITE);
        transparencyAttributes
                .setCapability(TransparencyAttributes.ALLOW_VALUE_READ);
        transparencyAttributes
                .setCapability(TransparencyAttributes.ALLOW_MODE_WRITE);
        if (transparency == 0) {
            transparencyAttributes
                    .setTransparencyMode(TransparencyAttributes.NONE);
        } else {
            transparencyAttributes
                    .setTransparencyMode(TransparencyAttributes.BLENDED);
            transparencyAttributes
                    .setSrcBlendFunction(TransparencyAttributes.BLEND_SRC_ALPHA);
        }
        transparencyAttributes.setTransparency(transparency);
        appearance.setTransparencyAttributes(transparencyAttributes);
        polygonAttributes.setCullFace(PolygonAttributes.CULL_NONE);
        appearance.setPolygonAttributes(polygonAttributes);
        // appearance.setColoringAttributes(coloringAttributes);

        logger.debug("forceCreation: " + forceCreation);
        if (value != value_buff || normalGenerator != normalGenerator_buff
                || forceCreation) {
            forceCreation = false;
            densityValue = chargeDensity.getDensity();
            ndiv = chargeDensity.getNumDiv();
            double lenmax = 1d;
            double[] jusin = new double[] { 0, 0, 0 };
            float[] fjusin = chargeDensity.getOrigin();
            if (tgatom instanceof TGAtom) {
                lenmax = ((TGAtom) tgatom).getLenMax();
                // jusin = ((TGAtom)tgatom).getCOM();
                jusin = ((TGAtom) tgatom).getConfigData().getCellOriginVector();
                double[] cellshift = ((TGAtom) tgatom).getCellOffset();
                for (int i = 0; i < 3; i++)
                    jusin[i] = -(jusin[i] + cellshift[i] * lenmax);
            } else if (fjusin != null) {
                jusin[0] = (double) fjusin[0];
                jusin[1] = (double) fjusin[1];
                jusin[2] = (double) fjusin[2];
            }

            coordinates = chargeDensity.getCoordinates();
            for (int j = 0; j < 3; j++) {
                jusin[j] /= lenmax;
                for (int i = 0; i < coordinates[j].length; i++) {
                    coordinates[j][i] /= lenmax;
                }
            }
            Point3f center = new Point3f((float) jusin[2], (float) jusin[1],
                    (float) jusin[0]);
            coordData.clear();
            normal.clear();
            try {
                mc.create_isosurf(coordinates[2], coordinates[1],
                        coordinates[0], ndiv[2], ndiv[1], ndiv[0],
                        densityValue, value, coordData, normal,
                        chargeDensity.getInterpolationScheme());
            } catch (Exception exc) {
                exc.printStackTrace();
            }
            value_buff = value;

            if (coordData.size() == 0) {
                logger.debug("no data crosses value...");
                return;
            }
            logger.debug("num. vertices: " + coordData.size());

            if (planes != null) {
                for (int i = 0; i < planes.length; i++) { // 面のx座標とz座標を入れ替える
                    logger.debug("plane no. " + i);
                    logger.debug(planes[i]);
                    Point3f nor = planes[i].getNormalVector();
                    planes[i].setNormalVector(new Point3f(nor.z, nor.y, nor.x));
                    Point3f ori = planes[i].getOrigin();
                    planes[i].setOrigin(new Point3f(ori.z, ori.y, ori.x));
                }
                int numTriangles = coordData.size() / 3;
                logger.debug("clipping isosurface; num. triangles: "
                        + numTriangles);
                Point3f genten = new Point3f();
                for (int i = numTriangles - 1; i >= 0; i--) {
                    Point3f[] points = new Point3f[3];
                    // Point3f point1 = new Point3f((Point3f)
                    // coordData.get(i*3));
                    // Point3f point2 = new Point3f((Point3f)
                    // coordData.get(i*3+1));
                    // Point3f point3 = new Point3f((Point3f)
                    // coordData.get(i*3+2));
                    Point3f point1 = (Point3f) coordData.get(i * 3);
                    Point3f point2 = (Point3f) coordData.get(i * 3 + 1);
                    Point3f point3 = (Point3f) coordData.get(i * 3 + 2);
                    point1.sub(center);
                    point2.sub(center);
                    point3.sub(center);
                    points[0] = point1;
                    points[1] = point2;
                    points[2] = point3;
                    float[] fromgenten = new float[3];
                    for (int j = 0; j < 3; j++) {
                        fromgenten[j] = points[j].distance(genten);
                    }
                    for (int k = 0; k < 2; k++) {
                        for (int l = k + 1; l < 3; l++) {
                            if (fromgenten[k] > fromgenten[l]) {
                                Point3f tmp1 = points[k];
                                Point3f tmp2 = points[l];
                                float tmptmp1 = fromgenten[k];
                                float tmptmp2 = fromgenten[l];
                                points[k] = tmp2;
                                points[l] = tmp1;
                                fromgenten[k] = tmptmp2;
                                fromgenten[l] = tmptmp1;
                            }
                        }
                    }
                    // System.out.println("point1, 2 and 3: "+points[0]+",
                    // "+points[1]+", "+points[2]);
                    int count1 = 0;
                    int count2 = 0;
                    int count3 = 0;
                    float nearest2 = 100000f;
                    float nearest3 = 100000f;
                    Plane nearestPlane2 = planes[0];
                    Plane nearestPlane3 = planes[0];
                    for (int j = 0; j < planes.length; j++) {
                        float d1 = planes[j].getDistanceFrom(genten);
                        float dp1 = planes[j].getDistanceFrom(points[0]);
                        float dp2 = planes[j].getDistanceFrom(points[1]);
                        float dp3 = planes[j].getDistanceFrom(points[2]);
                        if (Math.abs(dp2) < nearest2) {
                            nearest2 = Math.abs(dp2);
                            nearestPlane2 = planes[j];
                        }
                        if (Math.abs(dp3) < nearest3) {
                            nearest3 = Math.abs(dp3);
                            nearestPlane3 = planes[j];
                        }
                        // logger.debug("d1, dp1, dp2, dp3: "+d1+", "+dp1+",
                        // "+dp2+", "+dp3);
                        if (d1 > 0 && dp1 > 0 || d1 < 0 && dp1 < 0) {
                            count1++;
                        }
                        if (d1 > 0 && dp2 > 0 || d1 < 0 && dp2 < 0) {
                            count2++;
                        }
                        if (d1 > 0 && dp3 > 0 || d1 < 0 && dp3 < 0) {
                            count3++;
                        }
                    }

                    float one_plane_three = Math.abs(nearestPlane3
                            .getDistanceFrom(points[0]));
                    float two_plane_three = Math.abs(nearestPlane3
                            .getDistanceFrom(points[1]));
                    float one_plane_two = Math.abs(nearestPlane2
                            .getDistanceFrom(points[0]));

                    points[0].add(center);
                    points[1].add(center);
                    points[2].add(center);

                    if (count1 == planes.length && count2 == planes.length
                            && count3 == planes.length) { // この場合はなにもすることがない.
                        continue;
                    }
                    if (count1 != planes.length && count2 != planes.length
                            && count3 != planes.length) { /* 全頂点が境界の外; 外す */
                        coordData.remove(i * 3 + 2);
                        coordData.remove(i * 3 + 1);
                        coordData.remove(i * 3);
                        normal.remove(i * 3 + 2);
                        normal.remove(i * 3 + 1);
                        normal.remove(i * 3);
                    } else if ((count1 == planes.length
                            && count2 == planes.length && count3 != planes.length)) { /* 頂点の内一つは境界の外 */
                        float factor1 = one_plane_three
                                / (nearest3 + one_plane_three);
                        float factor2 = two_plane_three
                                / (nearest3 + two_plane_three);

                        Point3f newpoint1 = new Point3f(points[0]);
                        Point3f tmp1 = new Point3f(points[2]);
                        tmp1.sub(points[0]);
                        tmp1.scale(factor1);
                        newpoint1.add(tmp1);

                        Point3f newpoint2 = new Point3f(points[1]);
                        Point3f tmp2 = new Point3f(points[2]);
                        tmp2.sub(points[1]);
                        tmp2.scale(factor2);
                        newpoint2.add(tmp2);

                        points[2].sub(points[1]);
                        points[2].scale(factor2);
                        points[2].add(points[1]);

                        coordData.add(i * 3 + 3, points[0]);
                        coordData.add(i * 3 + 4, newpoint1);
                        coordData.add(i * 3 + 5, points[2]);

                        Vector3f v1 = (Vector3f) normal.get(i * 3);
                        Vector3f v2 = (Vector3f) normal.get(i * 3 + 1);
                        Vector3f v3 = (Vector3f) normal.get(i * 3 + 2);
                        normal.add(i * 3 + 3, v1);
                        normal.add(i * 3 + 4, v2);
                        normal.add(i * 3 + 5, v3);
                    } else if ((count1 == planes.length
                            && count2 != planes.length && count3 != planes.length)) { /* 頂点の内二つが境界の外 */
                        float factor1 = one_plane_two
                                / (nearest2 + one_plane_two);
                        float factor2 = one_plane_three
                                / (nearest3 + one_plane_three);
                        points[1].sub(points[0]);
                        points[1].scale(factor1);
                        points[1].add(points[0]);
                        points[2].sub(points[0]);
                        points[2].scale(factor2);
                        points[2].add(points[0]);
                        // coordData.set(i*3,points[0]);
                        // coordData.set(i*3+1,points[1]);
                        // coordData.set(i*3+2,points[2]);
                    } else { // もう, 上記以外は全部はずしてしまおう.
                        coordData.remove(i * 3 + 2);
                        coordData.remove(i * 3 + 1);
                        coordData.remove(i * 3);
                        normal.remove(i * 3 + 2);
                        normal.remove(i * 3 + 1);
                        normal.remove(i * 3);
                    }
                }
                for (int i = 0; i < planes.length; i++) { // 入れ替えたのを元に戻す
                    Point3f nor = planes[i].getNormalVector();
                    planes[i].setNormalVector(new Point3f(nor.z, nor.y, nor.x));
                    Point3f ori = planes[i].getOrigin();
                    planes[i].setOrigin(new Point3f(ori.z, ori.y, ori.x));
                }
            }
            // if ( firstQuadrantOnly ) {
            // Plane [] pl = new Plane [3];
            // Plane plane01 = new Plane();
            // Plane plane02 = new Plane();
            // Plane plane12 = new Plane();
            // pl[0] = plane01;
            // pl[1] = plane02;
            // pl[2] = plane12;
            // float [] norm01 =
            // VectorOperations.getNormalVector(axisVector[0],axisVector[1]);
            // float [] norm02 =
            // VectorOperations.getNormalVector(axisVector[0],axisVector[2]);
            // float [] norm12 =
            // VectorOperations.getNormalVector(axisVector[1],axisVector[2]);
            // plane01.setNormalVector(new Point3f(norm01));
            // plane02.setNormalVector(new Point3f(norm02));
            // plane12.setNormalVector(new Point3f(norm12));
            // float [][] nms = new float [3][];
            // nms[0] = norm01;
            // nms[1] = norm02;
            // nms[2] = norm12;
            //
            // for ( int ip=0 ; ip<3 ; ip++ ) {
            // int coordsize = coordData.size();
            // int numtri = coordData.size()/3;
            // for ( int i=0 ; i<numtri ; i++ ) {
            // Point3f newpoint1 = new Point3f((Point3f)coordData.get(3*i));
            // Point3f newpoint2 = new Point3f((Point3f)coordData.get(3*i+1));
            // Point3f newpoint3 = new Point3f((Point3f)coordData.get(3*i+2));
            // float d1 = -pl[ip].getDistanceFrom(newpoint1);
            // float d2 = -pl[ip].getDistanceFrom(newpoint2);
            // float d3 = -pl[ip].getDistanceFrom(newpoint3);
            // newpoint1.x += 2*nms[ip][0]*d1;
            // newpoint1.y += 2*nms[ip][1]*d1;
            // newpoint1.z += 2*nms[ip][2]*d1;
            // newpoint2.x += 2*nms[ip][0]*d2;
            // newpoint2.y += 2*nms[ip][1]*d2;
            // newpoint2.z += 2*nms[ip][2]*d2;
            // newpoint3.x += 2*nms[ip][0]*d3;
            // newpoint3.y += 2*nms[ip][1]*d3;
            // newpoint3.z += 2*nms[ip][2]*d3;
            //
            // Vector3f newnorm1 = new Vector3f((Vector3f)normal.get(3*i));
            // Vector3f newnorm2 = new Vector3f((Vector3f)normal.get(3*i+1));
            // Vector3f newnorm3 = new Vector3f((Vector3f)normal.get(3*i+2));
            // Point3f saki1 = new Point3f(newnorm1);
            // Point3f saki2 = new Point3f(newnorm2);
            // Point3f saki3 = new Point3f(newnorm3);
            // float nd1 = -pl[ip].getDistanceFrom(saki1);
            // float nd2 = -pl[ip].getDistanceFrom(saki2);
            // float nd3 = -pl[ip].getDistanceFrom(saki3);
            // newnorm1.x += 2*nms[ip][0]*nd1;
            // newnorm1.y += 2*nms[ip][1]*nd1;
            // newnorm1.z += 2*nms[ip][2]*nd1;
            // newnorm2.x += 2*nms[ip][0]*nd2;
            // newnorm2.y += 2*nms[ip][1]*nd2;
            // newnorm2.z += 2*nms[ip][2]*nd2;
            // newnorm3.x += 2*nms[ip][0]*nd3;
            // newnorm3.y += 2*nms[ip][1]*nd3;
            // newnorm3.z += 2*nms[ip][2]*nd3;
            //
            // coordData.add(newpoint1);
            // coordData.add(newpoint2);
            // coordData.add(newpoint3);
            // normal.add(newnorm1);
            // normal.add(newnorm2);
            // normal.add(newnorm3);
            // }
            // }
            //
            // }

            Point3f[] vertices = new Point3f[coordData.size()];
            Vector3f[] normals = new Vector3f[normal.size()];
            for (int j = 0; j < coordData.size(); j++) {
                Point3f tmp = (Point3f) coordData.get(j);
                vertices[j] = new Point3f(tmp.z - center.z, tmp.y - center.y,
                        tmp.x - center.x);
            }
            for (int j = 0; j < normals.length; j++) {
                Vector3f tmpn = (Vector3f) normal.get(j);
                normals[j] = tmpn;
                normals[j] = new Vector3f(tmpn.z, tmpn.y, tmpn.x);
            }

            boolean foo = true;
            try {
                foo = new Boolean(gp
                        .getProperty("isosurface_normal_generation").equals(
                                "j3d")).booleanValue();
            } catch (Exception exc) {
            }

            BranchGroup bg = null;
            if (normalGenerator == MC) {
                // pattr.setPolygonMode(PolygonAttributes.POLYGON_FILL);
                // pattr.setBackFaceNormalFlip(true);
                // coloringAttributes.setShadeModel(ColoringAttributes.SHADE_GOURAUD);

                GeometryInfo ginfo = new GeometryInfo(
                        GeometryInfo.TRIANGLE_ARRAY);
                ginfo.setCoordinates(vertices);
                ginfo.setNormals(normals);
                ginfo.recomputeIndices();
                Stripifier st = new Stripifier();
                st.stripify(ginfo);
                GeometryArray ara = ginfo.getGeometryArray();
                // ara.setNormals(0,normals);
                shape3D.setGeometry(ara);
                // TriangleArray triangleArray = new TriangleArray(
                // vertices.length, GeometryArray.COORDINATES
                // | GeometryArray.NORMALS);
                //
                // triangleArray.setCoordinates(0, vertices);
                // triangleArray.setNormals(0, normals);
                // try {
                // triangleArray.setCapability(TriangleArray.ALLOW_INTERSECT);
                // } catch (RestrictedAccessException rae) {
                // }
                // shape3D.setGeometry(triangleArray);
            } else if (normalGenerator == GINFO) {
                try {
                    GeometryInfo ginfo = new GeometryInfo(
                            GeometryInfo.TRIANGLE_ARRAY);
                    ginfo.setCoordinates(vertices);
                    ginfo.recomputeIndices();
                    NormalGenerator gen = new NormalGenerator();
                    gen.setCreaseAngle(Math.PI);
                    gen.generateNormals(ginfo);
                    Stripifier st = new Stripifier();
                    st.stripify(ginfo);
                    shape3D.setGeometry(ginfo.getGeometryArray());
                } catch (Exception exc) {
                    exc.printStackTrace();
                }
            }
            normalGenerator_buff = normalGenerator;
        }
    }

    public String toString() {
        return "no. " + String.valueOf(ID) + ", value: "
                + String.valueOf(value);
    }

    public void configDataUpdate() {
    }

    public void configDataUpdate(boolean rescaleOnUpdate,
            ConfigDataUpdateEvent e) {
        if (e.getType() == ConfigDataUpdateEvent.CELL_CHANGED) {
            detach();
            reset();
            createIsoSurface();
            parentPanel.getRootTransform().addChild(this);
        }
    }

    public boolean needsUpdate() {
        return true;
    }

}
