package votorola.s.gwt.scene.axial; // Copyright 2010, 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. import java.util.HashMap; import votorola.s.gwt.scene.*; import votorola.s.gwt.scene.feed.*; import votorola.s.gwt.scene.dum.*; // see 'temp' import votorola.s.gwt.stage.poll.*; import votorola.g.hold.*; /** A scene that situates polls in three dimensions according to activity (x), consensus (y) * and turnout (z). */ public final class TriaxialPollMap implements Scene, Hold { /** Constructs a TriaxialPollMap. Call {@linkplain #release release}() when done with it. */ public TriaxialPollMap() { for( final String pollName: Dummy.POLL_NAME_ARRAY ) // temp, FIX by asking server { polls.put( /*key*/pollName, new MappedPoll( pollName )); } } // ```````````````````````````````````````````````````````````````````````````````````` // init for early use private Spool spool = new Spool1(); // ------------------------------------------------------------------------------------ /** Tests whether the specified poll is within the current scope of this map. * * @see #inScope(BiteJS) */ boolean inScope( final MappedPoll poll ) { final float x = poll.x(); if( x < scoping.xMin() || x > scoping.xMax() ) return false; final float y = poll.y(); if( y < scoping.yMin() || y > scoping.yMax() ) return false; return true; } /** All known polls, keyed by poll name. * * @see Dummy#POLL_NAME_ARRAY */ HashMap polls() { return polls; } private final HashMap polls = new HashMap(); /** The scoping model for this map. */ DiaxialScoping scoping() { return scoping; } private final DiaxialScoping scoping = new DiaxialScoping( spool ); // - H o l d -------------------------------------------------------------------------- public void release() { spool.unwind(); } // - S c e n e ------------------------------------------------------------------------ /** {@inheritDoc} Only the x and y axes are variably scoped. {@linkplain * DiaxialScoping Diaxial scoping} is used for this purpose, q.v. for the format of * the 's' scoping switch. The z-axis remains unscoped, its full range always in * view. */ public boolean inScope( final BiteJS bite ) { final PollJS poll = bite.poll(); if( poll == null ) return false; final String pollName = poll.name(); if( pollName == null ) return false; final MappedPoll pollM = polls.get( pollName ); if( pollM == null ) return false; return inScope( pollM ); } // ==================================================================================== /** A poll together with its mapping particulars. */ static final class MappedPoll { private MappedPoll( String _name ) { name = _name; x = hash( name, 29 ); y = hash( name, 999331 ); z = hash( name, 443 ); } private float hash( final String s, final int prime ) { int i = 0; for( int c = s.length() - 1; c >= 0; --c ) { i = i * prime + s.charAt(c); i |= 0; // truncate to 32 bits when running in browser, where int is actually double } float f = Math.abs( i/(float)Integer.MAX_VALUE ); // if( f < 0f ) f = 0f; // else if( f >= 1f) f = Math.nextAfter( 1f, 0d ); // exclude 1.0 //// 'nextAfter' not available in client, but this is also valid: if( f < 0f || f >= 1f ) f = 0f; return f; } // -------------------------------------------------------------------------------- /** The name of this mapped poll. * * @see http://reluk.ca/project/_/outcast/pol.xht#poll-id-service */ public String name() { return name; } private final String name; /** The x-axis hash of the poll name. * * @return a number between 0.0 inclusive and 1.0 exclusive. */ float x() { return x; } private final float x; /** The y-axis hash of the poll name. * * @return a number between 0.0 inclusive and 1.0 exclusive. */ float y() { return y; } private final float y; /** The z-axis hash of the poll name. * * @return a number between 0.0 inclusive and 1.0 exclusive. */ float z() { return z; } private final float z; // - O b j e c t ------------------------------------------------------------------ public @Override String toString() { return "mapped poll " + name + "(" + x + "," + y + "," + z + ")"; } } }