View Javadoc

1   /* -------------------------------------------------------------------
2    * Java source file for the class NormalGenerator
3    * 
4    * Copyright (c), 2003, Masahiro Takatsuka.
5    * All Rights Researved.
6    * 
7    * Original Author: Masahiro Takatsuka (masa@jbeans.net)
8    * $Author: takatsukam $
9    * 
10   * $Date: 2004/03/03 11:53:06 $
11   * 
12   * $Id: NormalGenerator.java,v 1.3 2004/03/03 11:53:06 takatsukam Exp $
13   * 
14   * Reference:		Document no:
15   * ___				___
16   * 
17   * To Do:
18   * ___
19   * 
20  ------------------------------------------------------------------- */
21  
22  /* --------------------------- Package ---------------------------- */
23  package net.jbeans.j3d.modeler.geometry.util;
24  
25  /* ------------------ Import classes (packages) ------------------- *//package-summary/html">class="comment"> ------------------ Import classes (packages) ------------------- *//package-summary.html">class="comment">/* ------------------ Import classes (packages) ------------------- *//package-summary.html">class="comment"> ------------------ Import classes (packages) ------------------- */
26  import java.io.*;
27  import java.util.*;
28  import javax.media.j3d.*;
29  import javax.vecmath.*;
30  //import com.sun.j3d.utils.geometry.*;
31  
32  import net.jbeans.util.debug.*;
33  
34  /*====================================================================
35                 Implementation of class NormalGenerator                
36  ====================================================================*/
37  /***
38   * generally describe NormalGenerator in here
39   * 
40   * @version $Revision: 1.3 $
41   * @author Masahiro Takatsuka (masa@jbeans.net)
42   * @see com.sun.j3d.utils.geometry.NormalGenerator
43   */
44  
45  public class NormalGenerator extends com.sun.j3d.utils.geometry.NormalGenerator {
46  	private static final boolean DEBUG = Debug.getDebugFlag(NormalGenerator.class);
47  
48  	
49  	/* ------------------------ nor serialized ------------------------ */
50  	private transient Vector3f[] facetNorms;
51  	private transient ArrayList tally;
52  	private transient IndexedGeometryArray geomArray;
53  	private transient int[] coordInds;
54  	private transient int[] normalInds;
55  	private transient Vector3f[] normalRef;
56  	private transient EdgeTable edgetable;
57  	private transient boolean reset = true;
58  	private transient int indexCount = -1;
59  
60  	
61  	/* --------------------- tmp working buffers ---------------------- */
62  	private transient Vector3f workv3f0 = new Vector3f();
63  	private transient Vector3f workv3f1 = new Vector3f();	
64  	private transient int[] ai;
65  	private transient float cos;
66  	private transient Edge edge = new Edge();
67  	private transient Vector3f[] commonNormals;
68  	private transient Vector3f[] newNormals;
69  	
70  	public NormalGenerator() {
71  		super();
72  	}
73  
74  	public NormalGenerator(double d) {
75  		super(d);
76  	}
77  
78  	private int createHardEdges() {
79  		if (DEBUG) {
80  			System.out.println("Creating Hard Edges...");
81  		}
82  		if (reset) {
83  			this.edgetable = new EdgeTable(this.coordInds);
84  			this.tally = new ArrayList();
85  			this.ai = new int[this.coordInds.length];
86  			this.cos = (float)Math.cos(getCreaseAngle());
87  		} else {
88  			this.tally.clear();
89  		}
90  		for (int j = 0; j < this.coordInds.length; j++) {
91  			ai[j] = 0x7fffffff;
92  		}
93  		int i = 1;
94  		for (int k = 0; k < this.coordInds.length; k++) {
95  			if (ai[k] == 0x7fffffff) {
96  				ArrayList arraylist = new ArrayList();
97  				this.tally.add(arraylist);
98  				arraylist.add(new Integer(k));
99  				ai[k] = this.tally.size() - 1;
100 				boolean flag1 = true;
101 				this.edge.set(this.coordInds[k], this.coordInds[(k + 1) % 3 != 0 ? k + 1 : k - 2]);
102 				int l = this.coordInds[k % 3 != 0 ? k - 1 : k + 2];
103 				int i1 = k;
104 				boolean flag;
105 				do {
106 					Integer integer = this.edgetable.get(this.edge.v2, this.edge.v1);
107 					if (integer == null) {
108 						flag = false;
109 					} else {
110 						int j1 = integer.intValue();
111 						float f = this.facetNorms[i1 / 3].dot(this.facetNorms[j1 / 3]);
112 						flag = f > cos;
113 						if (flag) {
114 							int k1 = (((j1 + 1) % 3) != 0) ?
115 								(j1 + 1) : (j1 - 2);
116 							if (this.coordInds[k] != this.coordInds[k1]) {
117 								k1 = ((j1 % 3) != 0) ? (j1 - 1) : (j1 + 2);
118 							}
119 							if (ai[k1] != 0x7fffffff) {
120 								flag = false;
121 							} else {
122 								ai[k1] = this.tally.size() - 1;
123 								arraylist.add(new Integer(k1));
124 								if (arraylist.size() > i) {
125 									i = arraylist.size();
126 								}
127 								i1 = j1;
128 								if (flag1) {
129 									edge.v2 = this.coordInds[i1];
130 								} else {
131 									edge.v1 = this.coordInds[i1];
132 								}
133 							}
134 						}
135 					}
136 					if (!flag && flag1) {
137 						flag1 = false;
138 						flag = true;
139 						i1 = k;
140 						this.edge.set(this.coordInds[k % 3 != 0 ? k - 1 : k + 2], this.coordInds[k]);
141 					}
142 				} while(flag && (flag1 && edge.v2 != l || !flag1));
143 			}
144 		}
145 		return i;
146 	}
147 
148 	private void calculateVertexNormalsForGeometryArray(int totalNum) {
149 		if (DEBUG) {
150 			System.out.println("calculating vertex normals...");
151 		}
152 		boolean recycle = true;
153 		
154 		if (getCreaseAngle() != 0.0D) {
155 
156 			if (reset || (this.commonNormals.length < totalNum)) {
157 				this.commonNormals = new Vector3f[totalNum];
158 			}
159 			if (reset || (this.newNormals.length < this.tally.size())) {
160 				this.newNormals = new Vector3f[this.tally.size()];
161 				recycle = false;
162 			}
163 			//this.normalInds = new int[this.coordInds.length];
164 			if (DEBUG) {
165 				System.out.println("going through tally.");
166 			}
167 			for (int l = 0; l < this.tally.size(); l++) {
168 				ArrayList arraylist = (ArrayList)this.tally.get(l);
169 				int k = 0;
170 				if (!recycle) {
171 					this.newNormals[l] = new Vector3f();
172 				}
173 				for (int j1 = 0; j1 < arraylist.size(); j1++) {
174 					int k1 = ((Integer)arraylist.get(j1)).intValue();
175 					if (k1 != -1) {
176 						int j = k1 / 3;
177 						if (!Float.isNaN(this.facetNorms[j].x)) {
178 							int l1;
179 							for (l1 = 0; l1 < k; l1++) {
180 								if (this.commonNormals[l1].equals(this.facetNorms[j])) {
181 									break;
182 								}
183 							}
184 							
185 							this.normalInds[k1] = l;
186 							if (l1 == k) {
187 								this.newNormals[l].add(this.facetNorms[j]);
188 								this.commonNormals[k++] = this.facetNorms[j];
189 							}
190 						}
191 					}
192 				}
193 				
194 				this.newNormals[l].normalize();
195 				if (Float.isNaN(this.newNormals[l].x)) {
196 					this.newNormals[l].x = 1.0F;
197 					this.newNormals[l].y = this.newNormals[l].z = 0.0F;
198 				}
199 			}
200 		} else {
201 			this.newNormals = this.facetNorms;
202 			//this.normalInds = new int[this.facetNorms.length * 3];
203 			for (int i1 = 0; i1 < this.facetNorms.length; i1++) {
204 				this.normalInds[i1 * 3] = i1;
205 				this.normalInds[i1 * 3 + 1] = i1;
206 				this.normalInds[i1 * 3 + 2] = i1;
207 			}
208 			
209 		}
210 		if (DEBUG) {
211 			System.out.println("new index count = " + this.normalInds.length);
212 			System.out.println("new num of normalref = " + this.newNormals.length);
213 		}
214 		for (int i = 0; i < this.normalInds.length; i++) {
215 			this.normalRef[i] = this.newNormals[this.normalInds[i]];
216 		}
217 		if (DEBUG) {
218 			System.out.println("set new normals.");
219 		}
220 	}
221 
222 	private void calculatefacetNormalsForGeometryArray(Point3f[] apoint3f) {
223 		if (DEBUG) {
224 			System.out.println("calculating facet normals...");
225 		}
226 		if (DEBUG) {
227 			System.out.println("apoint3f length = " + apoint3f.length);
228 		}
229 		if (reset) {
230 			this.facetNorms = new Vector3f[this.coordInds.length / 3];
231 		}
232 		for (int i = 0; i < this.coordInds.length; i += 3) {
233 			workv3f0.sub(apoint3f[this.coordInds[i + 2]], apoint3f[this.coordInds[i + 1]]);
234 			workv3f1.sub(apoint3f[this.coordInds[i]], apoint3f[this.coordInds[i + 1]]);
235 			if (reset) {
236 				this.facetNorms[i / 3] = new Vector3f();
237 			}
238 			this.facetNorms[i / 3].cross(workv3f0, workv3f1);
239 			this.facetNorms[i / 3].normalize();
240 			if (Float.isNaN(this.facetNorms[i / 3].x)) {
241 				this.facetNorms[i / 3].x = 1.0F;
242 				this.facetNorms[i / 3].y = this.facetNorms[i / 3].z = 0.0F;
243 			}
244 		}
245 	}
246 	
247 	/***
248 	 * Computes naive normals. 
249 	 */
250 	public synchronized void generateNormals(GeometryArray geom, Point3f[] coords) {
251 		if (! checkIndexedGeometryArray(geom)) {
252 			return;
253 		}
254 		this.normalRef = geom.getNormalRef3f();
255 		this.geomArray = (IndexedGeometryArray) geom;
256 		int idxCount = this.geomArray.getIndexCount();
257 		if (this.indexCount != idxCount) {
258 			reset = true;
259 			this.indexCount = idxCount;
260 		} else {
261 			reset = false;
262 		}
263 		if (reset) {
264 			this.coordInds = new int[this.indexCount];
265 			this.geomArray.getCoordinateIndices(0, this.coordInds);
266 			this.normalInds = new int[this.indexCount];
267 			this.geomArray.getNormalIndices(0, this.normalInds);
268 		}
269 		calculatefacetNormalsForGeometryArray(coords);
270 		int i = createHardEdges();
271 		calculateVertexNormalsForGeometryArray(i);
272 	}
273 
274 	private boolean checkIndexedGeometryArray(GeometryArray geom) {
275 		if (! (geom instanceof IndexedTriangleArray ||
276 			   geom instanceof IndexedTriangleFanArray ||
277 			   geom instanceof IndexedTriangleStripArray)) {
278 			return false;
279 		}
280 		return true;
281 	}
282 }