Source code: com/trapezium/chisel/cleaners/KeyValueRemover.java
1 /*
2 * @(#)KeyValueRemover.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.vrml.VrmlElement;
14 import com.trapezium.vrml.fields.ISField;
15 import com.trapezium.vrml.fields.Field;
16 import com.trapezium.vrml.fields.MFFieldValue;
17 import com.trapezium.vrml.fields.FieldValue;
18 import com.trapezium.vrml.node.Node;
19 import com.trapezium.vrml.node.PROTO;
20 import com.trapezium.vrml.Scene;
21 import com.trapezium.chisel.*;
22
23 import java.util.BitSet;
24 import java.util.Hashtable;
25
26 /**
27 * The KeyValueRemover removes keys and corresponding keyValues if the
28 * following conditions are encountered:
29 *
30 * 1. a key of the form:
31 *
32 * ... a a a ....
33 * ^ this middle value (one or more) and corresponding
34 * keyValue entries are removed.
35 *
36 * 2. a keyValue of the form
37 *
38 * ... a a a ....
39 * ^ this middle keyValue (one or more) and corresponding
40 * key entries are removed.
41 *
42 * @author Johannes N. Johannsen
43 * @version b73, 1 July 1998
44 */
45
46 public class KeyValueRemover extends InterpolatorMinimizer {
47 protected Hashtable valueKillTable;
48 protected BitSet valueKillBits;
49
50 /** Class constructor, super class handles only keys */
51 public KeyValueRemover() {
52 super( "Removing unnecessary keyValues" );
53 valueKillTable = new Hashtable();
54 }
55
56 public void attemptOptimization( Node n ) {
57 Field key = n.getField( "key" );
58 Field keyValue = n.getField( "keyValue" );
59 // If either of these fields are in a PROTO and are defined with IS
60 // do nothing
61 VrmlElement nodeParent = n.getParent();
62 if ( nodeParent instanceof Scene ) {
63 VrmlElement grandParent = nodeParent.getParent();
64 if ( grandParent instanceof PROTO ) {
65 if ( key != null ) {
66 int firstKeyToken = key.getFirstTokenOffset();
67 if ( firstKeyToken != -1 ) {
68 int nextKeyToken = dataSource.getNextToken( firstKeyToken );
69 if ( nextKeyToken != -1 ) {
70 if ( dataSource.sameAs( nextKeyToken, "IS" )) {
71 return;
72 }
73 }
74 }
75 }
76 if ( keyValue != null ) {
77 int firstKeyToken = keyValue.getFirstTokenOffset();
78 if ( firstKeyToken != -1 ) {
79 int nextKeyToken = dataSource.getNextToken( firstKeyToken );
80 if ( nextKeyToken != -1 ) {
81 if ( dataSource.sameAs( nextKeyToken, "IS" )) {
82 return;
83 }
84 }
85 }
86 }
87 }
88 }
89
90 if ( key != null ) {
91 FieldValue keysfv = keyValue.getFieldValue();
92 MFFieldValue mfKeyValue = null;
93 if ( keysfv instanceof MFFieldValue ) {
94 mfKeyValue = (MFFieldValue)keysfv;
95 }
96 FieldValue keyFv = key.getFieldValue();
97 MFFieldValue mfKey = null;
98 if ( keyFv instanceof MFFieldValue ) {
99 mfKey = (MFFieldValue)keyFv;
100 }
101 if (( mfKeyValue != null ) && ( mfKeyValue.getRawValueCount() > 0 )) {
102 int factor = getInterpolatorFactor( n );
103 // here have to adjust factor for multiple-keyValue interpolators
104 int checkCount = mfKeyValue.getRawValueCount()/factor;
105 if ( checkCount > 0 ) {
106 if ( createBitSet( mfKey, mfKeyValue, checkCount, factor )) {
107 if ( replaceable( key )) {
108 if ( keyFv.getFirstTokenOffset() != -1 ) {
109 replaceRange( keyFv.getFirstTokenOffset(), keyFv.getLastTokenOffset(), new KeyInfo( n, Key, keyKillBits, valueKillBits, checkCount ));
110 }
111 }
112 if ( replaceable( keyValue )) {
113 FieldValue fv = keyValue.getFieldValue();
114 if ( fv.getFirstTokenOffset() != -1 ) {
115 replaceRange( fv.getFirstTokenOffset(), fv.getLastTokenOffset(), new KeyInfo( n, KeyValue, keyKillBits, valueKillBits, checkCount ));
116 }
117 }
118 }
119 }
120 }
121 }
122 }
123
124 /** Create if necessary the BitSets associated with a key field in
125 * an interpolator. The values "keyKillBits" and "valueKillBits"
126 * are initialized in either case.
127 *
128 * @param mfKey the interpolator key field
129 * @param mfKeyValue the interpolator keyValue field
130 * @param keyCount the number of key values
131 * @param factor how many numeric values associated with each keyValue entry
132 *
133 * @return true if there is something to remove, otherwise false
134 */
135 boolean createBitSet( MFFieldValue mfKey, MFFieldValue mfKeyValue, int keyCount, int factor ) {
136 if ( keyKillTable.get( mfKey ) != null ) {
137 keyKillBits = (BitSet)keyKillTable.get( mfKey );
138 valueKillBits = (BitSet)valueKillTable.get( mfKey );
139 // all value instances must agree on the removal
140 removeDups( valueKillBits, keyCount, mfKeyValue, factor, true );
141 return( true );
142 } else {
143 keyKillBits = new BitSet( keyCount );
144 valueKillBits = new BitSet( keyCount );
145 boolean result = removeDups( keyKillBits, keyCount, mfKey, 1, false );
146 result = removeDups( valueKillBits, keyCount, mfKeyValue, factor, false ) || result;
147 keyKillTable.put( mfKey, keyKillBits );
148 valueKillTable.put( mfKey, valueKillBits );
149 return( result );
150 }
151 }
152
153 /** Mark for removal middle entries in a sequence of identical entries.
154 *
155 * @param killBits the BitSet used to mark entries for removal
156 * @param numberEntries number of entries to check
157 * @param vals the entry values
158 * @param factor number of numeric values for each entry
159 * @param checkPreviousValues for keyValue removal, all PROTO instance
160 * keyValues must agree on the removal. If this parameter is true,
161 * previous values of the killBits are checked and possibly changed.
162 *
163 * @return true if there is anything marked, otherwise false
164 */
165 boolean removeDups( BitSet killBits, int numberEntries, MFFieldValue vals, int factor, boolean checkPreviousValues ) {
166 int ckcount = 0;
167 float[] currentVal = new float[ factor ];
168 float[] firstVal = new float[ factor ];
169 int numberConsecutiveValues = 0;
170 dataSource.setState( vals.getFirstTokenOffset() );
171 boolean result = false;
172 for ( int i = 0; i < numberEntries; i++ ) {
173 for ( int j = 0; j < factor; j++ ) {
174 int scanner = dataSource.skipNonNumbers();
175 float f = dataSource.getFloat( scanner );
176 if ( i == 0 ) {
177 firstVal[j] = f;
178 } else {
179 currentVal[ j ] = f;
180 }
181 scanner = dataSource.getNextToken();
182 }
183 if ( i > 0 ) {
184 boolean match = true;
185 for ( int j = 0; j < factor; j++ ) {
186 if ( firstVal[j] != currentVal[j] ) {
187 match = false;
188 break;
189 }
190 }
191 if ( match ) {
192 if ( numberConsecutiveValues == 0 ) {
193 numberConsecutiveValues = 2;
194 } else {
195 numberConsecutiveValues++;
196 }
197 } else {
198 numberConsecutiveValues = 0;
199 for ( int j = 0; j < factor; j++ ) {
200 firstVal[j] = currentVal[j];
201 }
202 }
203 }
204 if (( i > 0 ) && ( numberConsecutiveValues > 2 )) {
205 if ( !checkPreviousValues ) {
206 killBits.set( i - 1 );
207 }
208 result = true;
209 } else if ( checkPreviousValues ) {
210 if ( i > 0 ) {
211 killBits.clear( i - 1 );
212 }
213 }
214 }
215 return( result );
216 }
217 }