001package votorola.s.gwt.scene.axial; // Copyright 2010-2011, Michael Allan. Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Votorola Software"), to deal in the Votorola Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicence, and/or sell copies of the Votorola Software, and to permit persons to whom the Votorola Software is furnished to do so, subject to the following conditions: The preceding copyright notice and this permission notice shall be included in all copies or substantial portions of the Votorola Software. THE VOTOROLA SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE VOTOROLA SOFTWARE OR THE USE OR OTHER DEALINGS IN THE VOTOROLA SOFTWARE. 002 003import com.google.gwt.event.logical.shared.*; 004import com.google.web.bindery.event.shared.HandlerRegistration; 005import com.google.gwt.user.client.*; 006import votorola.s.gwt.scene.*; 007import votorola.g.hold.*; 008import votorola.g.lang.*; 009import votorola.g.web.gwt.*; 010 011 012/** A scoping model based on three orthogonal axes (x,y,z). Each axis may be set to its 013 * own independent range of values, such that all three ranges together specify a cubic 014 * sub-volume. The scoping state is exposed in the 's' scoping switch, as follows: 015 * 016 * <table class='definition' style='margin-left:1em'> 017 * <tr> 018 * <th class='key'>Switch</th> 019 * <th>Controlled state</th> 020 * <th>Default</th> 021 * </tr> 022 * <tr><td class='key'>s</td> 023 * 024 * <td>The scope control. 6 continguous numbers all padded to the same digit 025 * length, together representing the ranges of all three axes (x,y,z). Each 026 * number is translated to a decimal by adding a leading decimal. An exception 027 * is made for numbers beginning with the letter N, which are always translated 028 * as 1.0. For example "s=00NN103055NN" is taken as x in the range 0.00 to 1.00, 029 * y 0.10 to 0.30, and z 0.55 to 1.0.</td> 030 * 031 * <td>"0N0N0N" which specifies the full range on all three axes.</td> 032 * 033 * </tr> 034 * </table> 035 * 036 * @see Scoping 037 */ 038public final class TriaxialScoping implements Scoping 039{ 040 041 // cf. DiaxialScoping 042 043 044 /** Constructs a TriaxialScoping. 045 * 046 * @param spool for release of internal holds. When unwound, this instance will 047 * release its internal holds and become disabled. 048 */ 049 public TriaxialScoping( final Spool spool ) 050 { 051 spool.add( new Hold() 052 { 053 final HandlerRegistration hR = Scenes.i().sScopingSwitch().addHandler( 054 new ValueChangeHandler<String>() 055 { 056 public void onValueChange( final ValueChangeEvent<String> e ) 057 { 058 rescope( e.getValue() ); 059 GWTX.i().bus().fireEventFromSource( new ScopeChangeEvent(), TriaxialScoping.this ); 060 } 061 }); 062 public void release() { hR.removeHandler(); } 063 }); 064 rescope( Scenes.i().sScopingSwitch().get() ); // init state 065 } 066 067 068 069 // ------------------------------------------------------------------------------------ 070 071 072 /** The x-axis minimum value, inclusive. 073 * 074 * @return a number between 0.0 and 1.0 inclusive. 075 */ 076 public float xMin() { return xMin; } 077 078 079 private float xMin = 0f; 080 081 082 /** The x-axis maximum value, inclusive. 083 * 084 * @return a number between 0.0 and 1.0 inclusive. 085 */ 086 public float xMax() { return xMax; } 087 088 089 private float xMax = 1f; 090 091 092 093 /** The y-axis minimum value, inclusive. 094 * 095 * @return a number between 0.0 and 1.0 inclusive. 096 */ 097 public float yMin() { return yMin; } 098 099 100 private float yMin = 0f; 101 102 103 /** The y-axis maximum value, inclusive. 104 * 105 * @return a number between 0.0 and 1.0 inclusive. 106 */ 107 public float yMax() { return yMax; } 108 109 110 private float yMax = 1f; 111 112 113 114 /** The z-axis minimum value, inclusive. 115 * 116 * @return a number between 0.0 and 1.0 inclusive. 117 */ 118 public float zMin() { return zMin; } 119 120 121 private float zMin = 0f; 122 123 124 /** The z-axis maximum value, inclusive. 125 * 126 * @return a number between 0.0 and 1.0 inclusive. 127 */ 128 public float zMax() { return zMax; } 129 130 131 private float zMax = 1f; 132 133 134 135 // - O b j e c t ---------------------------------------------------------------------- 136 137 138 public @Override String toString() 139 { 140 return "triaxial scope = x(" + xMin + ", " + xMax + ") y(" + yMin + ", " + yMax 141 + ") z(" + zMin + ", " + zMax + ")"; 142 } 143 144 145 146 // - S c o p i n g -------------------------------------------------------------------- 147 148 149 public HandlerRegistration addHandler( final ScopeChangeHandler handler ) 150 { 151 return GWTX.i().bus().addHandlerToSource( ScopeChangeEvent.TYPE, 152 /*source*/TriaxialScoping.this, handler ); 153 } 154 155 156 157//// P r i v a t e /////////////////////////////////////////////////////////////////////// 158 159 160 private void rescopeToDefault() 161 { 162 xMin = 0f; xMax = 1f; 163 yMin = 0f; yMax = 1f; 164 zMin = 0f; zMax = 1f; 165 } 166 167 168 169 private @Warning("init call") void rescope( final String s ) 170 { 171 if( s == null ) 172 { 173 rescopeToDefault(); 174 return; 175 } 176 177 final int sLength = s.length(); 178 if( sLength % 6 > 0 ) 179 { 180 Window.alert( "Length of switch s not a multiple of 6: " + s ); 181 rescopeToDefault(); 182 return; 183 } 184 185 final int digitLength = sLength / 6; 186 final StringBuilder buf = new StringBuilder( 187 /*initial capacity*/DiaxialScoping.assumedNumericPrefix.length() + digitLength ); 188 buf.append( DiaxialScoping.assumedNumericPrefix ); 189 int digitOffset = 0; 190 try 191 { 192 xMin = DiaxialScoping.floatFrom( s, digitOffset, digitLength, buf ); digitOffset += digitLength; 193 xMax = DiaxialScoping.floatFrom( s, digitOffset, digitLength, buf ); digitOffset += digitLength; 194 yMin = DiaxialScoping.floatFrom( s, digitOffset, digitLength, buf ); digitOffset += digitLength; 195 yMax = DiaxialScoping.floatFrom( s, digitOffset, digitLength, buf ); digitOffset += digitLength; 196 zMin = DiaxialScoping.floatFrom( s, digitOffset, digitLength, buf ); digitOffset += digitLength; 197 zMax = DiaxialScoping.floatFrom( s, digitOffset, digitLength, buf ); 198 } 199 catch( NumberFormatException x ) 200 { 201 Window.alert( "Unable to parse switch s=" + s + ": " + x.toString() ); 202 rescopeToDefault(); 203 } 204 } 205 206 207}