package SModeling;

import java.util.Vector;

/** 
 *  Class which contains data for a convex polyhedral solid represented as
 *  a vertex-based B-rep (similar to a winged-edge).<p>
 *
 *  Portions of some methods based on code by James Gosling, relevant
 *  methods are marked.<p>
 *
 * <hr>
 * Copyright (c) 1995, H. Robert Frost, Stanford University.
 * All rights reserved.<p>
 * Copyright (c) 1996, H. Robert Frost, Enterprise Integration Technologies,
 * Inc. All rights reserved.<p>
 *
 * RESTRICTED RIGHTS LEGEND: Use, duplication or disclosure by the 
 * Government is subject to restrictions as set forth in 
 * subparagraph(c)(1)(ii) of the Rights in Technical Data and Computer
 * Software clause at DFARS 252.227-7013 and in similar clauses in the
 * FAR and NASA FAR supplement.<p>
 * 
 * This software is bound by the terms and conditions listed in the
 * attached <a href="../LICENSE">LICENSE file</A>.
 * <hr>
 * @author <A HREF="http://cdr.stanford.edu/html/people/frost-bio.html"> Rob Frost</A>
 * @version 5/21/96 for Java(tm) Language Version 1.0.2
 */

public class model {

  static final int CAP = 20, INCR = 5; /* capacity and increment
						 for Vectors */
  /**
   * Set of points which define the verticies of the model, type hpoint
   */
  public Vector verticies;

  /**
   * Indicies of lines which terminate at the vertex represented by the Vector
   * index, type Vector
   */
  public Vector vert_lines;

  /**
   * Planar convex polygonal faces of the model, type face
   */
  public Vector faces;
  
  /**
   * List of vertex indicies which form wireframe edges, type line
   */
  public Vector lines;

  /**
   * List of fixture points, type fix_point
   */
  public Vector fix_points;

  /**
   * Number of unique edges in the model
   */
  public int num_lines;

  /**
   * Number of verticies in the model
   */
  public int num_verticies;

  /**
   * Number of faces in the model
   */
  public int num_faces;

  /**
   * Currently selected fixture point
   */
  public int current_point=0;
 

  /**
   * Constructor for model. Creates all data storage objects.
   */

  public model () {
      
    verticies = new Vector(CAP, INCR);
    vert_lines = new Vector(CAP, INCR);
    faces = new Vector(CAP, INCR);
    lines = new Vector(CAP, INCR);
    fix_points = new Vector(CAP, INCR);
  }

  /**
   * Resets the models to zero fixture points
   */
  public void reset(){
    current_point = 0;
    fix_points = new Vector(CAP,INCR);
  }

  /**
   * Returns a string representation of the model.
   * @return String representation
   */
  public String toString(){
  
    String answer = "";
    
    answer = answer.concat("Verticies:\n");
    for(int i=0;i<num_verticies;i++){
      hpoint temp = (hpoint)verticies.elementAt(i);
      answer = answer.concat("v"+i+": "+(int)temp.getx()+","+(int)temp.gety()+","+
		    (int)temp.getz() + "\n");
    }
    return answer;
  }
  

 /**
  * Extracts edges, removes duplicates, stores lines for each face.
  * Called from the file parsing method.
  */
  public void ReduceModel() {
    num_verticies = verticies.size(); /* set num_verticies variable */
    num_faces = faces.size(); /* set num_faces variable */
    extract_lines(); /* get edge list */
    compress(); /* remove duplicate edges */
    num_lines = lines.size();
    create_face_lines();
    createInNorms();
  }   
  
  /**
   * Adds a vertex to the model. Called from the file parsing method.
   * @param vertex The hpoint to add as a new vertex.
   */
  public void add_vertex ( hpoint vertex) {
   // hpoint copy = (hpoint)vertex.clone();
    verticies.addElement(vertex);
    Boolean b = new Boolean(false);
  }
    
  /**
   * Adds a face to the model. Called from the file parsing method.
   * @param f Face to add to the model. 
   */
  public void add_face (face f) {
    faces.addElement(f);
  }
  
  /**
   * Extract vertex pairs which form lines from the face objects which form
   * the model, each line is stored as an array of two vertex indicies, 
   * lower index first
   */
  void extract_lines () {
    
    int p1, p2; /* dummy variables for indicies */
    face temp_face;
    int num_verts;
    
    for(int i = 0; i < num_faces; i++) {
      
      temp_face = (face)faces.elementAt(i);
      num_verts = temp_face.size();
      for(int j = 0; j < num_verts; j ++) {
	
	line temp_line;
	p1 = temp_face.getV(j);
	if(j >= num_verts -1) {
	  p2 = temp_face.getV(0);
	} else {
	  p2 = temp_face.getV(j+1);
	}
	if(p1 < p2) {
	  temp_line = new line(p1,p2);
	} else {
	  temp_line = new line(p2,p1);
	}
        temp_line.f1 = i; /* set first face indice to current face */
	lines.addElement(temp_line);
      }
    }
  }
  
  
  /**
   * Eliminate duplicate lines from the line list (all edges shared by two
   * faces can be represented only once). Based on code by James Gosling.
   */

  void compress() {

    int num_listed = lines.size();
    line comp;
    line temp;
    
    int i = 0;

    while(true) {
      if(i >= lines.size() -1) {
	break;
      }
      temp = (line)lines.elementAt(i++);
      int j = i;

      while(true) {
	comp = (line)lines.elementAt(j);
	if(comp.p1 == temp.p1 && comp.p2 == temp.p2) {
	  temp.f2 = comp.f1;
	  lines.setElementAt(temp, i-1);
	  lines.removeElementAt(j);
	} else {
	  j ++;
	}
	if(j >= lines.size()) {
	  break;
	}
	
      }
    }
  }

  /**
   * Create a Vector for every face which contains the indicies of
   * the edges which bound the face
   */
 
  void create_face_lines() {
     
    for(int i = 0; i< num_lines; i++) {
      line temp = (line)lines.elementAt(i);
      face f1 = (face)faces.elementAt(temp.f1);
      face f2 = (face)faces.elementAt(temp.f2);
      f1.addE(i+1);
      f2.addE(i+1);
    }
  
  }

  /**
   * Calculates the absolute inward normal vectors for all of the faces
   * in the model.
   */

  public void createInNorms(){
    for(int i = 0; i < num_faces; i++) {
      
	face temp = (face)faces.elementAt(i);
		
	hpoint p1 = (hpoint)verticies.elementAt(temp.getV(0)-1);
	hpoint p2 = (hpoint)verticies.elementAt(temp.getV(1)-1);
	hpoint p3 = (hpoint)verticies.elementAt(temp.getV(2)-1);
		
	hpoint e1 = p2.diff(p1);
	hpoint e2 = p3.diff(p2);
	
	e2.cross(e1);  
        temp.abs_in_norm = e2;
	temp.abs_in_norm.normalize();
      }
  }
    
  /**
   * Get the direction cosines for a fixture points inward normal vector.
   * Uses the absolute inward normal for each face (inward normal for
   * unrotated face).
   * @param fp Fixture point from which to extract the direction cosines.
   * @param index Determines which direction cosine to get, 1 for x-axis,
   *              2 for y-axis, 3 for z-axis.
   * @return Floating point value of direction cosine.
   */

  public float get_dircos(fix_point fp, int index) {
    face temp = (face)faces.elementAt(fp.face_index);
    hpoint dircos = temp.abs_in_norm.dircos();
    float answer = 0;
    if(index == 1) {
      answer = dircos.getx();
    } else if(index == 2) {
      answer = dircos.gety();
    } else if(index == 3) {
      answer = dircos.getz();
    } 
    return answer;
  }   
 

} /* end class model */







