Source code: com/trapezium/vrml/fields/Field.java
1 /*
2 * @(#)Field.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.vrml.fields;
12
13 import com.trapezium.parse.TokenEnumerator;
14 import com.trapezium.vrml.MultipleTokenElement;
15 import com.trapezium.vrml.VrmlElement;
16 import com.trapezium.vrml.FieldId;
17 import com.trapezium.vrml.Scene;
18 import com.trapezium.vrml.node.Node;
19 import com.trapezium.vrml.node.DEFUSENode;
20 import com.trapezium.vrml.node.NodeType;
21 import com.trapezium.vrml.grammar.VRML97;
22 import com.trapezium.pattern.Visitor;
23
24 /**
25 * Base class for all field instances.
26 *
27 * A Field is the range of tokens from the field id to the last token
28 * in the field value..
29 *
30 * @author Johannes N. Johannsen
31 * @version 1.1, 13 Jan 1998
32 *
33 * @since 1.0
34 */
35 public class Field extends MultipleTokenElement {
36 /** used only for indicating if PROTO field declarations are used by IS */
37 // need to move this over into PROTO interface vector
38 boolean inUse = false;
39 public void markInUse() {
40 inUse = true;
41 }
42 public boolean isInUse() {
43 return( inUse );
44 }
45
46 /** check if this field is an ISField */
47 public boolean isISfield() {
48 if ( fieldValue != null ) {
49 return( fieldValue.getChildAt( 0 ) instanceof ISField );
50 } else {
51 return( false );
52 }
53 }
54
55
56 /** base constructor */
57 public Field( int tokenOffset ) {
58 super( tokenOffset );
59 }
60
61 FieldValue fieldValue;
62
63 /** Get a FieldValue for this field */
64 public FieldValue getFieldValue() {
65 return( fieldValue );
66 }
67
68 public void setFieldValue( FieldValue fv ) {
69 fieldValue = fv;
70 if ( fv != null ) {
71 fieldValue.setParent( this );
72 }
73 }
74
75 public void fieldValueTraverse( Visitor v ) {
76 if ( fieldValue != null ) {
77 if ( v.isTwoPassVisitor() ) {
78 fieldValue.twoPassTraverse( v );
79 } else {
80 fieldValue.traverse( v );
81 }
82 }
83 }
84
85 /**
86 * Get a string identifying the type of this field.
87 */
88 int fieldType;
89 public int getFieldType() {
90 return( fieldType );
91 }
92 public void setFieldType( String fieldType ) {
93 setFieldType( VRML97.typeStrToInt( fieldType ));
94 }
95 public void setFieldType( int ft ) {
96 fieldType = ft;
97 }
98
99 /** Template, get the interface type
100 *
101 * @returns one of the following: VRML97.exposedField, VRML97.field,
102 * VRML97.eventIn, VRML97.eventOut
103 */
104 public int getInterfaceType() {
105 return( -1 );
106 }
107
108 String fieldId;
109
110 /** Get the name identifying this field */
111 public String getFieldId() {
112 return( fieldId );
113 }
114
115 /** Set the name identifying this field */
116 public void setFieldId( String id ) {
117 fieldId = id;
118 }
119
120 /** Get the Node that is the parent of this Field */
121 public Node getNodeParent() {
122 VrmlElement p = getParent();
123 while (( p != null ) && ( !( p instanceof Node ))) {
124 p = p.getParent();
125 }
126 if ( p != null ) {
127 return( (Node)p );
128 } else {
129 return( null );
130 }
131 }
132
133 /** Get the Node that is the field value of this field, bypassing DEF/USE */
134 public Node getNodeValue() {
135 // this is convenience routine for Fields representing Nodes
136 if ( fieldValue instanceof SFNodeValue ) {
137 VrmlElement node = fieldValue.getChildAt( 0 );
138 if ( node instanceof Node ) {
139 if ( node instanceof DEFUSENode ) {
140 node = ((DEFUSENode)node).getNode();
141 }
142 return( (Node)node );
143 }
144 }
145 return( null );
146 }
147
148 /** Get the Node that is the field value, returning DEF/USE if present */
149 public Node getNode() {
150 if ( fieldValue instanceof SFNodeValue ) {
151 VrmlElement node = fieldValue.getChildAt( 0 );
152 if ( node instanceof Node ) {
153 return( (Node)node );
154 }
155 }
156 return( null );
157 }
158
159 /** Get a float value at a particular offset in a list for this Field.
160 *
161 * @param dataSource TokenEnumerator containing data
162 * @param offset offset of the NumberToken to get the value for
163 * @return the float value at the offset
164 * @throws IndexOutOfBoundsException if the offset is outside token range
165 */
166 class GetFloatOptimizer {
167 final int SaveSize = 20;
168 int[] offsets;
169 int[] scannerValues;
170 int firstOffset;
171 int lastOffset;
172 int idx;
173
174 public GetFloatOptimizer( TokenEnumerator dataSource, int firstOffset, int lastOffset ) {
175 this.firstOffset = firstOffset;
176 this.lastOffset = lastOffset;
177 idx = 0;
178 offsets = new int[SaveSize];
179 scannerValues = new int[SaveSize];
180 idx = 0;
181 setup( dataSource );
182 }
183
184 void setup( TokenEnumerator dataSource ) {
185 int scanSize = ( lastOffset - firstOffset )/( SaveSize + 1 );
186 if ( scanSize <= 0 ) {
187 return;
188 }
189
190 int counter = 1;
191 int scanner = firstOffset;
192 dataSource.setState( scanner );
193 while ( scanner < lastOffset ) {
194 scanner = dataSource.skipToNumber( scanSize );
195 if ( scanner == -1 ) {
196 break;
197 }
198 offsets[ idx ] = scanSize*counter;
199 scannerValues[ idx ] = scanner;
200 idx++;
201 counter++;
202 if ( idx >= SaveSize ) {
203 break;
204 }
205 }
206 }
207
208
209 int skipToNumber( TokenEnumerator dataSource, int offset ) {
210 int originalOffset = offset;
211 int foundIdx = -1;
212 int foundDistance = -1;
213 for ( int i = 0; i < idx; i++ ) {
214 if ( offsets[i] < offset ) {
215 if ( foundIdx == -1 ) {
216 foundIdx = i;
217 foundDistance = offsets[i];
218 } else if ( offsets[i] > foundDistance ) {
219 foundIdx = i;
220 foundDistance = offsets[i];
221 }
222 } else {
223 break;
224 }
225 }
226 if ( foundIdx != -1 ) {
227 offset -= offsets[foundIdx];
228 dataSource.setState( scannerValues[foundIdx] );
229 } else {
230 dataSource.setState( firstOffset );
231 }
232 return( dataSource.skipToNumber( offset ));
233 }
234 }
235 transient GetFloatOptimizer getFloatOptimizer;
236 public float getFloat( TokenEnumerator dataSource, int offset ) throws IndexOutOfBoundsException {
237 if ( getFloatOptimizer == null ) {
238 getFloatOptimizer = new GetFloatOptimizer( dataSource, getFirstTokenOffset(), getLastTokenOffset() );
239 }
240 int oldState = dataSource.getState();
241 int scanner = getFloatOptimizer.skipToNumber( dataSource, offset );
242 // dataSource.setState( firstToken );
243 // int scanner = dataSource.skipToNumber( offset );
244 // if (( scanner >= lastToken ) || ( scanner == -1 )) {
245 if ( scanner == -1 ) {
246 dataSource.setState( oldState );
247 throw new IndexOutOfBoundsException( "Bad offset " + offset );
248 }
249 float result = dataSource.getFloat( scanner );
250 dataSource.setState( oldState );
251 return( result );
252 }
253
254 /** Clone a field value into a new Field */
255 protected void cloneFieldValue( Field result, VrmlElement protoInstance ) {
256 result.setFieldId( getFieldId() );
257 FieldValue fv = getFieldValue();
258 if ( fv != null ) {
259 FieldValue fvClone = (FieldValue)fv.vrmlClone( protoInstance );
260 VrmlElement preservedParent = null;
261 if ( fvClone == fv ) {
262 preservedParent = fv.getParent();
263 }
264 result.setFieldValue( fvClone );
265 if ( preservedParent != null ) {
266 fv.setParent( preservedParent );
267 }
268 }
269 }
270 }
271
272