Docjar: A Java Source and Docuemnt Enginecom.*    java.*    javax.*    org.*    all    new    plug-in

Quick Search    Search Deep

Source code: com/trapezium/chisel/cleaners/IFS_DupCoordDetector.java


1   /*
2    * @(#)IFS_DupCoordDetector.java
3    *
4    * Copyright (c) 1998 by Trapezium Development LLC.  All Rights Reserved.
5    *
6    * The information in this file is the property of Trapezium Development LLC
7    * and may be used only in accordance with the terms of the license granted
8    * by Trapezium.
9    *
10   */
11  package com.trapezium.chisel.cleaners;
12  
13  import com.trapezium.parse.TokenEnumerator;
14  import com.trapezium.vrml.VrmlElement;
15  import com.trapezium.vrml.Value;
16  import com.trapezium.vrml.node.Node;
17  import com.trapezium.vrml.node.DEFUSENode;
18  import com.trapezium.vrml.fields.Field;
19  import com.trapezium.vrml.fields.FieldValue;
20  import com.trapezium.vrml.fields.MFFieldValue;
21  import com.trapezium.chisel.*;
22  
23  import java.util.Vector;
24  import java.io.PrintStream;
25  
26  /**
27   *  Detects and removes unnecessarily duplicated values in a coord, texCoord, color,
28   *  or normal node.  These are not removed if the Coordinate/TextureCoordinate/Color/
29   *  Normal node are DEFfed and USEd by a ROUTE.  This is based on the assumption that
30   *  the ROUTE changes the values, therefore editting these affects the corresponding
31   *  "index" field, which exists for ROUTEd values and not for the pre-existing values.
32   *
33   *  @author          Johannes N. Johannsen
34   *  @version         1.0, 16 Oct 1998 (really older, just added header)
35   *
36   *  @since           1.0
37   */
38  
39  public class IFS_DupCoordDetector extends Optimizer {
40    int mergedPointCount = 0;
41    int modifiedFaceCount = 0;
42  
43    class CoordMergeData {
44      int[] offsets;
45      Vector[] vlistKey;
46      Vector[] vlistValue;
47  
48      public CoordMergeData( int[] offsets ) {
49        this.offsets = offsets;
50        vlistKey = new Vector[ 512 ];
51        vlistValue = new Vector[ 512 ];
52      }
53  
54      public int[] getOffsets() {
55        return( offsets );
56      }
57      
58      public void makeUnique( int offset ) {
59          offsets[ offset ] = offset;
60      }
61      
62      public void wipeout() {
63          vlistKey = null;
64          vlistValue = null;
65      }
66  
67        boolean arraysEqual( byte[] s1, byte[] s2 ) {
68            int len = s1.length;
69            for ( int i = 0; i < len; i++ ) {
70                if ( s1[i] != s2[i] ) {
71                    return( false );
72                }
73            }
74            return( true );
75        }
76      
77      public Integer get( byte[] key ) {
78          int offset = key[0];
79          if ( key.length > 3 ) {
80              offset += (key[1] + key[2] + key[3]);
81          }
82          offset += key[ key.length - 1 ];
83            offset = offset & 0x1ff;
84            Vector keyVector = vlistKey[ offset ];
85            if ( keyVector != null ) {
86                int keyVecSize = keyVector.size();
87                for ( int i = 0; i < keyVecSize; i++ ) {
88                    byte[] entry = (byte[])keyVector.elementAt( i );
89                    if ( entry.length == key.length ) {
90                        if ( arraysEqual( entry, key )) {
91                            Vector valueVector = vlistValue[ offset ];
92                            return( (Integer)valueVector.elementAt( i ));
93                        }
94                    }
95                }
96            }
97          return( null );
98      }
99       
100     public void put( byte[] key, Integer keyValue ) {
101         int offset = key[0];
102         if ( key.length > 3 ) {
103             offset += (key[1] + key[2] + key[3]);
104         }
105         offset += key[ key.length - 1 ];
106           offset = offset & 0x1ff;
107         if ( vlistKey[ offset ] == null ) {
108             vlistKey[ offset ] = new Vector();
109             vlistValue[ offset ] = new Vector();
110         }
111           vlistKey[ offset ].addElement( key );
112           vlistValue[ offset ].addElement( keyValue );
113       }
114         
115   }
116 
117     /** Class constructor */
118   public IFS_DupCoordDetector() {
119     super( "CoordinateOwner", "Removing duplicate values..." );
120   }
121   
122   class CharArrayContainer {
123       char[] charArray;
124       CharArrayContainer( char[] a ) {
125           charArray = a;
126       }
127       public char[] getCharArray() {
128           return( charArray );
129       }
130   }
131 
132 int totalMadeUnique = 0;
133   public void attemptOptimization( Node n ) {
134       CoordMergeData coord_cmd = attemptOptimization( n, "coord", "coordIndex", "point" );
135       CoordMergeData tex_cmd = attemptOptimization( n, "texCoord", "texCoordIndex", "point" );
136       CoordMergeData clr_cmd = attemptOptimization( n, "color", "colorIndex", "color" );
137       CoordMergeData normal_cmd = attemptOptimization( n, "normal", "normalIndex", "vector" );
138       
139       // adjust coord_cmd based on texCoord (see comment below)
140       if (( coord_cmd != null ) && ( tex_cmd != null ) && ( n.getField( "texCoordIndex" ) == null )) {
141           // this means there is no texCoordIndex, and texCoord maps one-to-one with coords.
142           // So if there is a coord merge, and the texCoords are not the same, then we
143           // have to undo the coord merge
144           int[] coordOffsets = coord_cmd.getOffsets();
145           int[] texCoordOffsets = tex_cmd.getOffsets();
146           int numberCoords = coordOffsets.length;
147           int numberTexCoords = texCoordOffsets.length;
148           int count = numberCoords;
149           if ( numberTexCoords < count ) {
150               count = numberTexCoords;
151           }
152           int discrepancyCount = 0;
153           int mergeCount = 0;
154           for ( int i = 0; i < count; i++ ) {
155               if ( coordOffsets[i] != i ) {
156                   mergeCount++;
157                   if ( texCoordOffsets[i] != texCoordOffsets[coordOffsets[i]] ) {
158                       discrepancyCount++;
159                       coord_cmd.makeUnique( i );
160                   }
161               }
162           }
163           totalMadeUnique += discrepancyCount;
164      //     System.out.println( "mergeCount " + mergeCount + ", discrepancyCount " + discrepancyCount + ", totalMadeUnique " + totalMadeUnique );
165       }
166   }
167   
168   /**
169    *  This needs some work, when the CoordMergeData gets made, the
170    *  offsets need to be readjusted, depending on how the related sets
171    *  get merged.  For example, "texCoord" alone map one-to-one with
172    *  coordinates if there is no "texCoordIndex".  In this case, the
173    *  offsets of the two arrays must match exactly.  Any place they don't
174    *  match must be un-optimized.
175    *
176    *  @param n the Node to optimize
177    *  @param nodeFieldName the name of the IFS node field to attempt optimization for,
178    *     possible values are "coord", "normal", "color", "texCoord"
179    *  @param indexName the name of the index field that corresponds to the node field,
180    *     possible values are "coordIndex", "normalIndex", "colorIndex", "texCoordIndex"
181    *  @param valueName the name of the field within the value node containing values
182    *
183    *  @return a CoordMergeData object used during the actual optimization.  If the
184    *     Node is DEFfed and USEd by a ROUTE, it is not optimized, and null is returned.
185    */
186   CoordMergeData attemptOptimization( Node n, String nodeFieldName, String indexName, String valueName ) {
187       if ( n.isFieldUsedByROUTE( nodeFieldName )) {
188           return( null );
189       }
190     Field coord = n.getField( nodeFieldName );
191     Field coordIndex = n.getField( indexName );
192     int factor = 3;
193     if ( nodeFieldName.compareTo( "texCoord" ) == 0 ) {
194         factor = 2;
195     }
196     if ( coord != null ) {
197       FieldValue fv = coord.getFieldValue();
198       Node coordNode = (Node)fv.getChildAt( 0 );
199       if ( coordNode instanceof DEFUSENode ) {
200         DEFUSENode dun = (DEFUSENode)coordNode;
201         coordNode = dun.getNode();
202       }
203       if ( coordNode != null ) {
204         MFFieldValue coordValues = null;
205         Field coords = coordNode.getField( valueName );
206         if ( coords == null ) {
207             return( null );
208         }
209         if ( coords.isISfield() ) {
210             return( null );
211         }
212         FieldValue cfv = coords.getFieldValue();
213         if ( cfv instanceof MFFieldValue ) {
214             coordValues = (MFFieldValue)cfv;
215 //            System.out.println( "raw value count " + coordValues.getRawValueCount() + ", factor " + factor );
216           }
217           if ( coordValues == null ) {
218               return( null );
219           }
220           int numberCoords = coordValues.getRawValueCount()/factor;
221           if ( numberCoords < 2 ) {
222               return( null );
223           }
224         int[] offsets = new int[ numberCoords ];
225         for ( int i = 0; i < numberCoords; i++ ) {
226           offsets[i] = i;
227         }
228         int scannerOffset = coords.getFirstTokenOffset();
229         int endOffset = coords.getLastTokenOffset();
230         CoordMergeData cmd = new CoordMergeData( offsets );
231         int coordNumber = 0;
232         while ( true ) {
233           if ( dataSource.isNumber( scannerOffset )) {
234             int n1 = scannerOffset;
235             int n2 = dataSource.getNextToken( n1 );
236             if ( factor == 3 ) {
237                 int n3 = dataSource.getNextToken( n2 );
238                 byte[] result = dataSource.getCharArray( n1, n2, n3 );
239                 Integer iresult = cmd.get( result );
240                 if ( iresult == null ) {
241                     cmd.put( result, new Integer( coordNumber ));
242                 } else {
243                     offsets[ coordNumber ] = iresult.intValue();
244                     mergedPointCount++;
245                 }
246                 coordNumber++;
247                 scannerOffset = n3;
248               } else {
249                   byte[] result = dataSource.getCharArray( n1, n2 );
250                   Integer iresult = cmd.get( result );
251                   if ( iresult == null ) {
252                       cmd.put( result, new Integer( coordNumber ));
253                   } else {
254                       offsets[ coordNumber ] = iresult.intValue();
255                       mergedPointCount++;
256                   }
257                   coordNumber++;
258                   scannerOffset = n2;
259               }
260           }
261           if ( scannerOffset == endOffset ) {
262             break;
263           }
264           if ( coordNumber >= numberCoords ) {
265               break;
266           }
267           scannerOffset = dataSource.getNextToken( scannerOffset );
268           if ( scannerOffset == -1 ) {
269               return( null );
270           }
271         }
272         cmd.wipeout();
273         if ( coordIndex != null ) {
274             replaceRange( coordIndex.getFirstTokenOffset(), coordIndex.getLastTokenOffset(), cmd );
275           }
276         return( cmd );
277       }
278     }
279     return( null );
280   }
281   
282   /** Replace index values so that they only refer to a coordinate with a given
283    *  value one way.  Duplicate coordinates then end up not being referenced, which
284    *  allows them to be clean with the IFS_CoordRemover chisel.
285    *
286    *  @param tp print destination
287    *  @param param coordinate merge info
288    *  @param startTokenOffset first offset in the range of tokens to replace
289    *  @param endTokenOffset last offset in the range of tokens to replace
290    */
291   public void optimize( TokenPrinter tp, Object param, int startTokenOffset, int endTokenOffset ) {
292     int scannerOffset = startTokenOffset;
293     CoordMergeData cmd = (CoordMergeData)param;
294     int[] offsets = cmd.getOffsets();
295     int offsetSize = offsets.length;
296     boolean modifiedFace = false;
297     dataSource.setState( scannerOffset );
298     while ( scannerOffset != -1 ) {
299       if ( dataSource.isNumber( scannerOffset )) {
300         int ival = dataSource.getIntValue( scannerOffset );
301         if ( ival == -1 ) {
302           tp.print( dataSource, scannerOffset );
303           modifiedFace = false;
304         } else if (( ival >= 0 ) && ( ival < offsetSize )) {
305           tp.print( offsets[ ival ] );
306           if ( offsets[ ival ] != ival ) {
307             if ( !modifiedFace ) {
308               modifiedFaceCount++;
309               modifiedFace = true;
310             }
311           }
312         }
313       } else {
314         tp.print( dataSource, scannerOffset );
315       }
316       if ( scannerOffset == endTokenOffset ) {
317         break;
318       }
319       scannerOffset = dataSource.getNextToken( scannerOffset );
320     }
321   }
322 
323   public void summarize( PrintStream ps ) {
324     ps.println( "mergedPointCount is " + mergedPointCount );
325     ps.println( "modifiedFaceCount is " + modifiedFaceCount );
326   }
327 }
328 
329