Small improvements to Local Index Activity. Made search faster

This commit is contained in:
Victor Shcherb 2011-09-25 18:20:11 +02:00
parent fccd27d426
commit 71baf5a7af
8 changed files with 2254 additions and 70 deletions

View file

@ -0,0 +1,341 @@
///////////////////////////////////////////////////////////////////////////////
// Copyright (c) 2001, Eric D. Friedman All Rights Reserved.
// Copyright (c) 2009, Rob Eden All Rights Reserved.
// Copyright (c) 2009, Jeff Randall All Rights Reserved.
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; either
// version 2.1 of the License, or (at your option) any later version.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
///////////////////////////////////////////////////////////////////////////////
package gnu.trove.impl.hash;
import gnu.trove.procedure.*;
import gnu.trove.impl.HashFunctions;
import java.io.ObjectOutput;
import java.io.ObjectInput;
import java.io.IOException;
//////////////////////////////////////////////////
// THIS IS A GENERATED CLASS. DO NOT HAND EDIT! //
//////////////////////////////////////////////////
/**
* An open addressed hashing implementation for int/long primitive entries.
*
* Created: Sun Nov 4 08:56:06 2001
*
* @author Eric D. Friedman
* @author Rob Eden
* @author Jeff Randall
* @version $Id: _K__V_Hash.template,v 1.1.2.6 2009/11/07 03:36:44 robeden Exp $
*/
abstract public class TIntLongHash extends TPrimitiveHash {
/** the set of ints */
public transient int[] _set;
/**
* key that represents null
*
* NOTE: should not be modified after the Hash is created, but is
* not final because of Externalization
*
*/
protected int no_entry_key;
/**
* value that represents null
*
* NOTE: should not be modified after the Hash is created, but is
* not final because of Externalization
*
*/
protected long no_entry_value;
/**
* Creates a new <code>T#E#Hash</code> instance with the default
* capacity and load factor.
*/
public TIntLongHash() {
super();
no_entry_key = ( int ) 0;
no_entry_value = ( long ) 0;
}
/**
* Creates a new <code>T#E#Hash</code> instance whose capacity
* is the next highest prime above <tt>initialCapacity + 1</tt>
* unless that value is already prime.
*
* @param initialCapacity an <code>int</code> value
*/
public TIntLongHash( int initialCapacity ) {
super( initialCapacity );
no_entry_key = ( int ) 0;
no_entry_value = ( long ) 0;
}
/**
* Creates a new <code>TIntLongHash</code> instance with a prime
* value at or near the specified capacity and load factor.
*
* @param initialCapacity used to find a prime capacity for the table.
* @param loadFactor used to calculate the threshold over which
* rehashing takes place.
*/
public TIntLongHash( int initialCapacity, float loadFactor ) {
super(initialCapacity, loadFactor);
no_entry_key = ( int ) 0;
no_entry_value = ( long ) 0;
}
/**
* Creates a new <code>TIntLongHash</code> instance with a prime
* value at or near the specified capacity and load factor.
*
* @param initialCapacity used to find a prime capacity for the table.
* @param loadFactor used to calculate the threshold over which
* rehashing takes place.
* @param no_entry_value value that represents null
*/
public TIntLongHash( int initialCapacity, float loadFactor,
int no_entry_key, long no_entry_value ) {
super(initialCapacity, loadFactor);
this.no_entry_key = no_entry_key;
this.no_entry_value = no_entry_value;
}
/**
* Returns the value that is used to represent null as a key. The default
* value is generally zero, but can be changed during construction
* of the collection.
*
* @return the value that represents null
*/
public int getNoEntryKey() {
return no_entry_key;
}
/**
* Returns the value that is used to represent null. The default
* value is generally zero, but can be changed during construction
* of the collection.
*
* @return the value that represents null
*/
public long getNoEntryValue() {
return no_entry_value;
}
/**
* initializes the hashtable to a prime capacity which is at least
* <tt>initialCapacity + 1</tt>.
*
* @param initialCapacity an <code>int</code> value
* @return the actual capacity chosen
*/
protected int setUp( int initialCapacity ) {
int capacity;
capacity = super.setUp( initialCapacity );
_set = new int[capacity];
return capacity;
}
/**
* Searches the set for <tt>val</tt>
*
* @param val an <code>int</code> value
* @return a <code>boolean</code> value
*/
public boolean contains( int val ) {
return index(val) >= 0;
}
/**
* Executes <tt>procedure</tt> for each key in the map.
*
* @param procedure a <code>TIntProcedure</code> value
* @return false if the loop over the set terminated because
* the procedure returned false for some value.
*/
public boolean forEach( TIntProcedure procedure ) {
byte[] states = _states;
int[] set = _set;
for ( int i = set.length; i-- > 0; ) {
if ( states[i] == FULL && ! procedure.execute( set[i] ) ) {
return false;
}
}
return true;
}
/**
* Releases the element currently stored at <tt>index</tt>.
*
* @param index an <code>int</code> value
*/
protected void removeAt( int index ) {
_set[index] = no_entry_key;
super.removeAt( index );
}
/**
* Locates the index of <tt>val</tt>.
*
* @param key an <code>int</code> value
* @return the index of <tt>val</tt> or -1 if it isn't in the set.
*/
protected int index( int key ) {
int hash, probe, index, length;
final byte[] states = _states;
final int[] set = _set;
length = states.length;
hash = HashFunctions.hash( key ) & 0x7fffffff;
index = hash % length;
if ( states[index] != FREE &&
( states[index] == REMOVED || set[index] != key ) ) {
// see Knuth, p. 529
probe = 1 + ( hash % ( length - 2 ) );
do {
index -= probe;
if ( index < 0 ) {
index += length;
}
} while ( states[index] != FREE &&
( states[index] == REMOVED || set[index] != key ) );
}
return states[index] == FREE ? -1 : index;
}
/**
* Locates the index at which <tt>val</tt> can be inserted. if
* there is already a value equal()ing <tt>val</tt> in the set,
* returns that value as a negative integer.
*
* @param key an <code>int</code> value
* @return an <code>int</code> value
*/
protected int insertionIndex( int key ) {
int hash, probe, index, length;
final byte[] states = _states;
final int[] set = _set;
length = states.length;
hash = HashFunctions.hash( key ) & 0x7fffffff;
index = hash % length;
if ( states[index] == FREE ) {
return index; // empty, all done
} else if ( states[index] == FULL && set[index] == key ) {
return -index -1; // already stored
} else { // already FULL or REMOVED, must probe
// compute the double hash
probe = 1 + ( hash % ( length - 2 ) );
// if the slot we landed on is FULL (but not removed), probe
// until we find an empty slot, a REMOVED slot, or an element
// equal to the one we are trying to insert.
// finding an empty slot means that the value is not present
// and that we should use that slot as the insertion point;
// finding a REMOVED slot means that we need to keep searching,
// however we want to remember the offset of that REMOVED slot
// so we can reuse it in case a "new" insertion (i.e. not an update)
// is possible.
// finding a matching value means that we've found that our desired
// key is already in the table
if ( states[index] != REMOVED ) {
// starting at the natural offset, probe until we find an
// offset that isn't full.
do {
index -= probe;
if (index < 0) {
index += length;
}
} while ( states[index] == FULL && set[index] != key );
}
// if the index we found was removed: continue probing until we
// locate a free location or an element which equal()s the
// one we have.
if ( states[index] == REMOVED) {
int firstRemoved = index;
while ( states[index] != FREE &&
( states[index] == REMOVED || set[index] != key ) ) {
index -= probe;
if (index < 0) {
index += length;
}
}
return states[index] == FULL ? -index -1 : firstRemoved;
}
// if it's full, the key is already stored
return states[index] == FULL ? -index -1 : index;
}
}
/** {@inheritDoc} */
public void writeExternal( ObjectOutput out ) throws IOException {
// VERSION
out.writeByte( 0 );
// SUPER
super.writeExternal( out );
// NO_ENTRY_KEY
out.writeInt( no_entry_key );
// NO_ENTRY_VALUE
out.writeLong( no_entry_value );
}
/** {@inheritDoc} */
public void readExternal( ObjectInput in ) throws IOException, ClassNotFoundException {
// VERSION
in.readByte();
// SUPER
super.readExternal( in );
// NO_ENTRY_KEY
no_entry_key = in.readInt();
// NO_ENTRY_VALUE
no_entry_value = in.readLong();
}
} // TIntLongHash

View file

@ -0,0 +1,115 @@
///////////////////////////////////////////////////////////////////////////////
// Copyright (c) 2001, Eric D. Friedman All Rights Reserved.
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; either
// version 2.1 of the License, or (at your option) any later version.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
///////////////////////////////////////////////////////////////////////////////
package gnu.trove.iterator;
//////////////////////////////////////////////////
// THIS IS A GENERATED CLASS. DO NOT HAND EDIT! //
//////////////////////////////////////////////////
/**
* Iterator for maps of type int and long.
*
* <p>The iterator semantics for Trove's primitive maps is slightly different
* from those defined in <tt>java.util.Iterator</tt>, but still well within
* the scope of the pattern, as defined by Gamma, et al.</p>
*
* <p>This iterator does <b>not</b> implicitly advance to the next entry when
* the value at the current position is retrieved. Rather, you must explicitly
* ask the iterator to <tt>advance()</tt> and then retrieve either the <tt>key()</tt>,
* the <tt>value()</tt> or both. This is done so that you have the option, but not
* the obligation, to retrieve keys and/or values as your application requires, and
* without introducing wrapper objects that would carry both. As the iteration is
* stateful, access to the key/value parts of the current map entry happens in
* constant time.</p>
*
* <p>In practice, the iterator is akin to a "search finger" that you move from
* position to position. Read or write operations affect the current entry only and
* do not assume responsibility for moving the finger.</p>
*
* <p>Here are some sample scenarios for this class of iterator:</p>
*
* <pre>
* // accessing keys/values through an iterator:
* for ( TIntLongIterator it = map.iterator(); it.hasNext(); ) {
* it.advance();
* if ( satisfiesCondition( it.key() ) {
* doSomethingWithValue( it.value() );
* }
* }
* </pre>
*
* <pre>
* // modifying values in-place through iteration:
* for ( TIntLongIterator it = map.iterator(); it.hasNext(); ) {
* it.advance();
* if ( satisfiesCondition( it.key() ) {
* it.setValue( newValueForKey( it.key() ) );
* }
* }
* </pre>
*
* <pre>
* // deleting entries during iteration:
* for ( TIntLongIterator it = map.iterator(); it.hasNext(); ) {
* it.advance();
* if ( satisfiesCondition( it.key() ) {
* it.remove();
* }
* }
* </pre>
*
* <pre>
* // faster iteration by avoiding hasNext():
* TIntLongIterator iterator = map.iterator();
* for ( int i = map.size(); i-- > 0; ) {
* iterator.advance();
* doSomethingWithKeyAndValue( iterator.key(), iterator.value() );
* }
* </pre>
*/
public interface TIntLongIterator extends TAdvancingIterator {
/**
* Provides access to the key of the mapping at the iterator's position.
* Note that you must <tt>advance()</tt> the iterator at least once
* before invoking this method.
*
* @return the key of the entry at the iterator's current position.
*/
public int key();
/**
* Provides access to the value of the mapping at the iterator's position.
* Note that you must <tt>advance()</tt> the iterator at least once
* before invoking this method.
*
* @return the value of the entry at the iterator's current position.
*/
public long value();
/**
* Replace the value of the mapping at the iterator's position with the
* specified value. Note that you must <tt>advance()</tt> the iterator at
* least once before invoking this method.
*
* @param val the value to set in the current entry
* @return the old value of the entry.
*/
public long setValue( long val );
}

View file

@ -0,0 +1,303 @@
///////////////////////////////////////////////////////////////////////////////
// Copyright (c) 2009, Rob Eden All Rights Reserved.
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; either
// version 2.1 of the License, or (at your option) any later version.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
///////////////////////////////////////////////////////////////////////////////
package gnu.trove.map;
//////////////////////////////////////////////////
// THIS IS A GENERATED CLASS. DO NOT HAND EDIT! //
//////////////////////////////////////////////////
import gnu.trove.function.*;
import gnu.trove.iterator.*;
import gnu.trove.procedure.*;
import gnu.trove.set.*;
import gnu.trove.TLongCollection;
import java.util.Map;
import java.io.Serializable;
/**
* Interface for a primitive map of int keys and long values.
*/
public interface TIntLongMap extends Serializable {
/**
* Returns the value that will be returned from {@link #get} or {@link #put} if no
* entry exists for a given key. The default value is generally zero, but can be
* changed during construction of the collection.
*
* @return the value that represents a null key in this collection.
*/
public int getNoEntryKey();
/**
* Returns the value that will be returned from {@link #get} or {@link #put} if no
* entry exists for a given key. The default value is generally zero, but can be
* changed during construction of the collection.
*
* @return the value that represents a null value in this collection.
*/
public long getNoEntryValue();
/**
* Inserts a key/value pair into the map.
*
* @param key an <code>int</code> value
* @param value an <code>long</code> value
*
* @return the previous value associated with <tt>key</tt>, or the "no entry" value
* if none was found (see {@link #getNoEntryValue}).
*/
public long put( int key, long value );
/**
* Inserts a key/value pair into the map if the specified key is not already
* associated with a value.
*
* @param key an <code>int</code> value
* @param value an <code>long</code> value
*
* @return the previous value associated with <tt>key</tt>, or the "no entry" value
* if none was found (see {@link #getNoEntryValue}).
*/
public long putIfAbsent( int key, long value );
/**
* Put all the entries from the given Map into this map.
*
* @param map The Map from which entries will be obtained to put into this map.
*/
public void putAll( Map<? extends Integer, ? extends Long> map );
/**
* Put all the entries from the given map into this map.
*
* @param map The map from which entries will be obtained to put into this map.
*/
public void putAll( TIntLongMap map );
/**
* Retrieves the value for <tt>key</tt>
*
* @param key an <code>int</code> value
*
* @return the previous value associated with <tt>key</tt>, or the "no entry" value
* if none was found (see {@link #getNoEntryValue}).
*/
public long get( int key );
/**
* Empties the map.
*/
public void clear();
/**
* Returns <tt>true</tt> if this map contains no key-value mappings.
*
* @return <tt>true</tt> if this map contains no key-value mappings
*/
public boolean isEmpty();
/**
* Deletes a key/value pair from the map.
*
* @param key an <code>int</code> value
*
* @return the previous value associated with <tt>key</tt>, or the "no entry" value
* if none was found (see {@link #getNoEntryValue}).
*/
public long remove( int key );
/**
* Returns an <tt>int</tt> value that is the number of elements in the map.
*
* @return an <tt>int</tt> value that is the number of elements in the map.
*/
public int size();
/**
* Returns the keys of the map as a <tt>TIntSet</tt>
*
* @return the keys of the map as a <tt>TIntSet</tt>
*/
public TIntSet keySet();
/**
* Returns the keys of the map as an array of <tt>int</tt> values.
*
* @return the keys of the map as an array of <tt>int</tt> values.
*/
public int[] keys();
/**
* Returns the keys of the map.
*
* @param array the array into which the elements of the list are to be stored,
* if it is big enough; otherwise, a new array of the same type is
* allocated for this purpose.
* @return the keys of the map as an array.
*/
public int[] keys( int[] array );
/**
* Returns the values of the map as a <tt>TLongCollection</tt>
*
* @return the values of the map as a <tt>TLongCollection</tt>
*/
public TLongCollection valueCollection();
/**
* Returns the values of the map as an array of <tt>#e#</tt> values.
*
* @return the values of the map as an array of <tt>#e#</tt> values.
*/
public long[] values();
/**
* Returns the values of the map using an existing array.
*
* @param array the array into which the elements of the list are to be stored,
* if it is big enough; otherwise, a new array of the same type is
* allocated for this purpose.
* @return the values of the map as an array of <tt>#e#</tt> values.
*/
public long[] values( long[] array );
/**
* Checks for the presence of <tt>val</tt> in the values of the map.
*
* @param val an <code>long</code> value
* @return a <code>boolean</code> value
*/
public boolean containsValue( long val );
/**
* Checks for the present of <tt>key</tt> in the keys of the map.
*
* @param key an <code>int</code> value
* @return a <code>boolean</code> value
*/
public boolean containsKey( int key );
/**
* @return a TIntLongIterator with access to this map's keys and values
*/
public TIntLongIterator iterator();
/**
* Executes <tt>procedure</tt> for each key in the map.
*
* @param procedure a <code>TIntProcedure</code> value
* @return false if the loop over the keys terminated because
* the procedure returned false for some key.
*/
public boolean forEachKey( TIntProcedure procedure );
/**
* Executes <tt>procedure</tt> for each value in the map.
*
* @param procedure a <code>T#F#Procedure</code> value
* @return false if the loop over the values terminated because
* the procedure returned false for some value.
*/
public boolean forEachValue( TLongProcedure procedure );
/**
* Executes <tt>procedure</tt> for each key/value entry in the
* map.
*
* @param procedure a <code>TOIntLongProcedure</code> value
* @return false if the loop over the entries terminated because
* the procedure returned false for some entry.
*/
public boolean forEachEntry( TIntLongProcedure procedure );
/**
* Transform the values in this map using <tt>function</tt>.
*
* @param function a <code>TLongFunction</code> value
*/
public void transformValues( TLongFunction function );
/**
* Retains only those entries in the map for which the procedure
* returns a true value.
*
* @param procedure determines which entries to keep
* @return true if the map was modified.
*/
public boolean retainEntries( TIntLongProcedure procedure );
/**
* Increments the primitive value mapped to key by 1
*
* @param key the key of the value to increment
* @return true if a mapping was found and modified.
*/
public boolean increment( int key );
/**
* Adjusts the primitive value mapped to key.
*
* @param key the key of the value to increment
* @param amount the amount to adjust the value by.
* @return true if a mapping was found and modified.
*/
public boolean adjustValue( int key, long amount );
/**
* Adjusts the primitive value mapped to the key if the key is present in the map.
* Otherwise, the <tt>initial_value</tt> is put in the map.
*
* @param key the key of the value to increment
* @param adjust_amount the amount to adjust the value by
* @param put_amount the value put into the map if the key is not initial present
*
* @return the value present in the map after the adjustment or put operation
*/
public long adjustOrPutValue( int key, long adjust_amount, long put_amount );
}

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,42 @@
///////////////////////////////////////////////////////////////////////////////
// Copyright (c) 2001, Eric D. Friedman All Rights Reserved.
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; either
// version 2.1 of the License, or (at your option) any later version.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
///////////////////////////////////////////////////////////////////////////////
package gnu.trove.procedure;
//////////////////////////////////////////////////
// THIS IS A GENERATED CLASS. DO NOT HAND EDIT! //
//////////////////////////////////////////////////
/**
* Interface for procedures that take two parameters of type int and long.
*/
public interface TIntLongProcedure {
/**
* Executes this procedure. A false return value indicates that
* the application executing this procedure should not invoke this
* procedure again.
*
* @param a a <code>int</code> value
* @param b a <code>long</code> value
* @return true if additional invocations of the procedure are
* allowed.
*/
public boolean execute( int a, long b );
}

View file

@ -1,13 +1,17 @@
package net.osmand.binary;
import gnu.trove.list.array.TIntArrayList;
import gnu.trove.map.hash.TIntLongHashMap;
import gnu.trove.set.hash.TLongHashSet;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import org.apache.commons.logging.Log;
import net.osmand.Algoritms;
import net.osmand.LogUtil;
import net.osmand.binary.BinaryMapIndexReader.SearchRequest;
import net.osmand.data.Amenity;
import net.osmand.data.AmenityType;
@ -19,6 +23,7 @@ import com.google.protobuf.CodedInputStreamRAF;
import com.google.protobuf.WireFormat;
public class BinaryMapPoiReaderAdapter {
private static final Log LOG = LogUtil.getLog(BinaryMapPoiReaderAdapter.class);
public static final int SHIFT_BITS_CATEGORY = 7;
private static final int CATEGORY_MASK = (1 << SHIFT_BITS_CATEGORY) - 1 ;
@ -154,7 +159,8 @@ public class BinaryMapPoiReaderAdapter {
protected void searchPoiIndex(int left31, int right31, int top31, int bottom31,
SearchRequest<Amenity> req, PoiRegion region) throws IOException {
int indexOffset = codedIS.getTotalBytesRead();
TIntArrayList offsets = new TIntArrayList();
long time = System.currentTimeMillis();
TIntLongHashMap offsetsMap = new TIntLongHashMap();
while(true){
if(req.isInterrupted()){
return;
@ -167,21 +173,24 @@ public class BinaryMapPoiReaderAdapter {
case OsmandOdb.OsmAndPoiIndex.BOXES_FIELD_NUMBER :
int length = readInt();
int oldLimit = codedIS.pushLimit(length);
readBoxField(left31, right31, top31, bottom31, 0, 0, 0, offsets, req, region);
readBoxField(left31, right31, top31, bottom31, 0, 0, 0, offsetsMap, req, region);
codedIS.popLimit(oldLimit);
break;
case OsmandOdb.OsmAndPoiIndex.POIDATA_FIELD_NUMBER :
offsets.sort();
int[] offsets = offsetsMap.keys();
Arrays.sort(offsets);
TLongHashSet skipTiles = null;
List<Amenity> temporaryList = new ArrayList<Amenity>();
int zoomToSkip = 31;
if(req.zoom != -1){
skipTiles = new TLongHashSet();
zoomToSkip = req.zoom + ZOOM_TO_SKIP_FILTER;
}
List<Amenity> temporaryList = new ArrayList<Amenity>();
LOG.info("Searched poi structure in "+(System.currentTimeMillis() - time) +
"ms. Found " + offsets.length +" subtress");
for (int j = 0; j < offsets.size(); j++) {
codedIS.seek(offsets.get(j) + indexOffset);
for (int j = 0; j < offsets.length; j++) {
codedIS.seek(offsets[j] + indexOffset);
int len = readInt();
int oldLim = codedIS.pushLimit(len);
@ -190,15 +199,29 @@ public class BinaryMapPoiReaderAdapter {
readPoiData(left31, right31, top31, bottom31, req, req.getSearchResults(), region,
skipTiles, zoomToSkip);
} else {
temporaryList.clear();
readPoiData(left31, right31, top31, bottom31, req, temporaryList, region, skipTiles, zoomToSkip);
for(Amenity a : temporaryList){
int x = (int) MapUtils.getTileNumberX(zoomToSkip, a.getLocation().getLongitude());
int y = (int) MapUtils.getTileNumberY(zoomToSkip, a.getLocation().getLatitude());
long val = (((long) x) << zoomToSkip) | y;
if(!skipTiles.contains(val)){
skipTiles.add(val);
req.getSearchResults().add(a);
long box = offsetsMap.get(offsets[j]);
int z = (int) (box & 31);
boolean skipBox = false;
if (z >= zoomToSkip) {
int yt = (int) ((box >> 5) & ((1 << z) - 1));
int xt = (int) (box >> (5 + z));
long val = ((((long) xt) >> (z - zoomToSkip)) << zoomToSkip) | (((long) yt) >> (z - zoomToSkip));
skipBox = skipTiles.contains(val);
}
if(skipBox){
codedIS.skipRawBytes(codedIS.getBytesUntilLimit());
} else {
temporaryList.clear();
readPoiData(left31, right31, top31, bottom31, req, temporaryList, region, skipTiles, zoomToSkip);
for (Amenity a : temporaryList) {
int x = (int) MapUtils.getTileNumberX(zoomToSkip, a.getLocation().getLongitude());
int y = (int) MapUtils.getTileNumberY(zoomToSkip, a.getLocation().getLatitude());
long val = (((long) x) << zoomToSkip) | y;
if (!skipTiles.contains(val)) {
skipTiles.add(val);
req.getSearchResults().add(a);
}
}
}
}
@ -370,7 +393,7 @@ public class BinaryMapPoiReaderAdapter {
}
private void readBoxField(int left31, int right31, int top31, int bottom31,
int px, int py, int pzoom, TIntArrayList offsets, SearchRequest<Amenity> req, PoiRegion region) throws IOException {
int px, int py, int pzoom, TIntLongHashMap offsetsMap, SearchRequest<Amenity> req, PoiRegion region) throws IOException {
req.numberOfReadSubtrees++;
boolean checkBox = true;
int zoom = pzoom;
@ -409,7 +432,7 @@ public class BinaryMapPoiReaderAdapter {
}
break;
case OsmandOdb.OsmAndPoiBox.SUBBOXES_FIELD_NUMBER:
case OsmandOdb.OsmAndPoiBox.SUBBOXES_FIELD_NUMBER: {
int x = dx + (px << (zoom - pzoom));
int y = dy + (py << (zoom - pzoom));
if(checkBox){
@ -427,13 +450,15 @@ public class BinaryMapPoiReaderAdapter {
}
int length = readInt();
int oldLimit = codedIS.pushLimit(length);
readBoxField(left31, right31, top31, bottom31, x, y, zoom, offsets, req, region);
readBoxField(left31, right31, top31, bottom31, x, y, zoom, offsetsMap, req, region);
codedIS.popLimit(oldLimit);
break;
case OsmandOdb.OsmAndPoiBox.SHIFTTODATA_FIELD_NUMBER:
offsets.add(readInt());
break;
} break;
case OsmandOdb.OsmAndPoiBox.SHIFTTODATA_FIELD_NUMBER: {
int x = dx + (px << (zoom - pzoom));
int y = dy + (py << (zoom - pzoom));
long l = ((((x << zoom) | y) << 5) | zoom);
offsetsMap.put(readInt(), l);
} break;
default:
skipUnknownField(t);
break;

View file

@ -1,5 +1,7 @@
<?xml version="1.0" encoding="utf-8" standalone="no"?>
<resources>
<string name="local_index_mi_rename">Rename</string>
<string name="show_gpx_route">Show on map</string>
<string name="poi_filter_nominatim">Online Nominatim</string>
<string name="auto_follow_route_never">Never</string>
<string name="choose_auto_follow_route">Choose auto follow settings </string>

View file

@ -59,6 +59,7 @@ public class LocalIndexesActivity extends ExpandableListActivity {
private boolean selectionMode = false;
private Set<LocalIndexInfo> selectedItems = new LinkedHashSet<LocalIndexInfo>();
private OsmandSettings settings;
protected static int DELETE_OPERATION = 1;
protected static int BACKUP_OPERATION = 2;
@ -66,6 +67,8 @@ public class LocalIndexesActivity extends ExpandableListActivity {
MessageFormat formatMb = new MessageFormat("{0, number,##.#} MB", Locale.US);
MessageFormat formatGb = new MessageFormat("{0, number,#.##} GB", Locale.US);
@SuppressWarnings("unchecked")
@Override
@ -74,6 +77,7 @@ public class LocalIndexesActivity extends ExpandableListActivity {
// requestWindowFeature(Window.FEATURE_NO_TITLE);
setContentView(R.layout.local_index);
settings = OsmandSettings.getOsmandSettings(this);
descriptionLoader = new LoadLocalIndexDescriptionTask();
listAdapter = new LocalIndexesAdapter();
Object indexes = getLastNonConfigurationInstance();
@ -100,22 +104,82 @@ public class LocalIndexesActivity extends ExpandableListActivity {
int child = ExpandableListView.getPackedPositionChild(packedPos);
if (child >= 0 && group >= 0) {
final LocalIndexInfo point = (LocalIndexInfo) listAdapter.getChild(group, child);
if (point != null && point.getGpxFile() != null) {
WptPt loc = point.getGpxFile().findPointToShow();
if (loc != null) {
OsmandSettings.getOsmandSettings(LocalIndexesActivity.this).setMapLocationToShow(loc.lat,
loc.lon);
}
((OsmandApplication) getApplication()).setGpxFileToDisplay(point.getGpxFile());
MapActivity.launchMapActivityMoveToTop(LocalIndexesActivity.this);
}
showContextMenu(point);
}
}
}
});
setListAdapter(listAdapter);
updateDescriptionTextWithSize();
}
private void showContextMenu(final LocalIndexInfo info) {
Builder builder = new AlertDialog.Builder(this);
final List<Integer> menu = new ArrayList<Integer>();
if(info.getGpxFile() != null && info.getType() == LocalIndexType.GPX_DATA){
menu.add(R.string.show_gpx_route);
menu.add(R.string.local_index_mi_upload_gpx);
}
if(info.getType() == LocalIndexType.MAP_DATA || info.getType() == LocalIndexType.POI_DATA){
if(!info.isBackupedData()){
menu.add(R.string.local_index_mi_backup);
}
}
if(info.isBackupedData()){
menu.add(R.string.local_index_mi_restore);
}
menu.add(R.string.local_index_mi_rename);
menu.add(R.string.local_index_mi_delete);
if (!menu.isEmpty()) {
String[] values = new String[menu.size()];
for (int i = 0; i < values.length; i++) {
values[i] = getString(menu.get(i));
}
builder.setItems(values, new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
int resId = menu.get(which);
if (resId == R.string.show_gpx_route) {
if (info != null && info.getGpxFile() != null) {
WptPt loc = info.getGpxFile().findPointToShow();
if (loc != null) {
OsmandSettings.getOsmandSettings(LocalIndexesActivity.this).setMapLocationToShow(loc.lat, loc.lon);
}
((OsmandApplication) getApplication()).setGpxFileToDisplay(info.getGpxFile());
MapActivity.launchMapActivityMoveToTop(LocalIndexesActivity.this);
}
} else if (resId == R.string.local_index_mi_rename) {
// TODO
} else if (resId == R.string.local_index_mi_restore) {
boolean successfull = move(new File(info.getPathToData()), getFileToRestore(info));
if(successfull){
info.setBackupedData(false);
reloadIndexes();
}
listAdapter.move(new LocalIndexInfo[] {info}, true);
} else if (resId == R.string.local_index_mi_delete) {
File f = new File(info.getPathToData());
boolean successfull = Algoritms.removeAllFiles(f);
if(successfull){
listAdapter.delete(new LocalIndexInfo[] {info});
reloadIndexes();
}
} else if (resId == R.string.local_index_mi_backup) {
boolean successfull = move(new File(info.getPathToData()), getFileToBackup(info));
if(successfull){
info.setBackupedData(true);
reloadIndexes();
}
listAdapter.move(new LocalIndexInfo[] {info}, false);
} else if (resId == R.string.local_index_mi_upload_gpx) {
// TODO
}
}
});
}
builder.show();
}
public class LoadLocalIndexTask extends AsyncTask<Activity, LocalIndexInfo, List<LocalIndexInfo>> {
@ -165,50 +229,49 @@ public class LocalIndexesActivity extends ExpandableListActivity {
}
private File getFileToRestore(LocalIndexInfo i){
if(i.isBackupedData()){
File parent = new File(i.getPathToData()).getParentFile();
if(i.getType() == LocalIndexType.GPX_DATA){
parent = settings.extendOsmandPath(ResourceManager.GPX_PATH);
} else if(i.getType() == LocalIndexType.MAP_DATA){
parent = settings.extendOsmandPath(ResourceManager.MAPS_PATH);
} else if(i.getType() == LocalIndexType.POI_DATA){
parent = settings.extendOsmandPath(ResourceManager.POI_PATH);
} else if(i.getType() == LocalIndexType.TILES_DATA){
parent = settings.extendOsmandPath(ResourceManager.TILES_PATH);
} else if(i.getType() == LocalIndexType.VOICE_DATA){
parent = settings.extendOsmandPath(ResourceManager.VOICE_PATH);
} else if(i.getType() == LocalIndexType.TTS_VOICE_DATA){
parent = settings.extendOsmandPath(ResourceManager.VOICE_PATH);
}
return new File(parent, i.getFileName());
}
return new File(i.getPathToData());
}
private File getFileToBackup(LocalIndexInfo i) {
if(!i.isBackupedData()){
return new File(settings.extendOsmandPath(ResourceManager.BACKUP_PATH), i.getFileName());
}
return new File(i.getPathToData());
}
private boolean move(File from, File to){
if(!to.getParentFile().exists()){
to.getParentFile().mkdirs();
}
return from.renameTo(to);
}
public class LocalIndexOperationTask extends AsyncTask<LocalIndexInfo, LocalIndexInfo, String> {
private final int operation;
private OsmandSettings settings;
public LocalIndexOperationTask(int operation){
this.operation = operation;
settings = ((OsmandApplication) getApplication()).getSettings();
}
public File getFileToRestore(LocalIndexInfo i){
if(i.isBackupedData()){
File parent = new File(i.getPathToData()).getParentFile();
if(i.getType() == LocalIndexType.GPX_DATA){
parent = settings.extendOsmandPath(ResourceManager.GPX_PATH);
} else if(i.getType() == LocalIndexType.MAP_DATA){
parent = settings.extendOsmandPath(ResourceManager.MAPS_PATH);
} else if(i.getType() == LocalIndexType.POI_DATA){
parent = settings.extendOsmandPath(ResourceManager.POI_PATH);
} else if(i.getType() == LocalIndexType.TILES_DATA){
parent = settings.extendOsmandPath(ResourceManager.TILES_PATH);
} else if(i.getType() == LocalIndexType.VOICE_DATA){
parent = settings.extendOsmandPath(ResourceManager.VOICE_PATH);
} else if(i.getType() == LocalIndexType.TTS_VOICE_DATA){
parent = settings.extendOsmandPath(ResourceManager.VOICE_PATH);
}
return new File(parent, i.getFileName());
}
return new File(i.getPathToData());
}
private File getFileToBackup(LocalIndexInfo i) {
if(!i.isBackupedData()){
return new File(settings.extendOsmandPath(ResourceManager.BACKUP_PATH), i.getFileName());
}
return new File(i.getPathToData());
}
private boolean move(File from, File to){
if(!to.getParentFile().exists()){
to.getParentFile().mkdirs();
}
return from.renameTo(to);
}
@Override
protected String doInBackground(LocalIndexInfo... params) {