nanomap/monav/gpsgrid/cell.h

287 lines
10 KiB
C++

/*
Copyright 2010 Christian Vetter veaac.fdirct@gmail.com
This file is part of MoNav.
MoNav is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
MoNav 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 General Public License
along with MoNav. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef CELL_H
#define CELL_H
#include "utils/config.h"
#include "utils/coordinates.h"
#include "utils/bithelpers.h"
#include "utils/edgeconnector.h"
#include <vector>
#include <algorithm>
namespace gg
{
class Cell {
public:
struct Edge {
unsigned pathID;
unsigned short pathLength;
unsigned short edgeID;
NodeID source;
NodeID target;
bool bidirectional;
bool operator==( const Edge& right ) const {
if ( source != right.source )
return false;
if ( target != right.target )
return false;
if ( bidirectional != right.bidirectional )
return false;
if ( edgeID != right.edgeID )
return false;
if ( pathLength != right.pathLength )
return false;
return true;
}
};
std::vector< Edge > edges;
std::vector< UnsignedCoordinate > coordinates;
bool operator==( const Cell& right ) const
{
if ( edges.size() != right.edges.size() )
return false;
for ( int i = 0; i < ( int ) edges.size(); i++ ) {
if ( !( edges[i] == right.edges[i] ) )
return false;
for ( unsigned path = 0; path < edges[i].pathLength; path++ ) {
if ( coordinates[path + edges[i].pathID].x != right.coordinates[path + right.edges[i].pathID].x )
return false;
if ( coordinates[path + edges[i].pathID].y != right.coordinates[path + right.edges[i].pathID].y )
return false;
}
}
return true;
}
size_t write( unsigned char* buffer, UnsignedCoordinate min, UnsignedCoordinate max )
{
unsigned char* const oldBuffer = buffer;
NodeID minID = std::numeric_limits< NodeID >::max();
NodeID maxID = 0;
unsigned short maxEdgeID = 0;
unsigned short maxPathLength = 0;
{
// build edge connector data structures
std::vector< EdgeConnector< unsigned >::Edge > connectorEdges;
std::vector< unsigned > resultSegments;
std::vector< unsigned > resultSegmentDescriptions;
std::vector< bool > resultReversed;
for ( unsigned i = 0; i < ( unsigned ) edges.size(); i++ ) {
EdgeConnector< unsigned >::Edge newEdge;
newEdge.source = edges[i].source;
newEdge.target = edges[i].target;
newEdge.reverseable = edges[i].bidirectional;
connectorEdges.push_back( newEdge );
}
EdgeConnector< unsigned >::run( &resultSegments, &resultSegmentDescriptions, &resultReversed, connectorEdges );
for ( unsigned i = 0; i < ( unsigned ) edges.size(); i++ ) {
if ( resultReversed[i] ) {
std::swap( edges[i].source, edges[i].target );
std::reverse( coordinates.begin() + edges[i].pathID, coordinates.begin() + edges[i].pathID + edges[i].pathLength );
}
}
std::vector< Edge > reorderedEdges;
for ( unsigned i = 0; i < ( unsigned ) resultSegmentDescriptions.size(); i++ )
reorderedEdges.push_back( edges[resultSegmentDescriptions[i]] );
edges.swap( reorderedEdges );
}
std::vector< NodeID > nodes;
for ( std::vector< Edge >::iterator i = edges.begin(), e = edges.end(); i != e; ++i ) {
minID = std::min( minID, i->source );
minID = std::min( minID, i->target );
maxID = std::max( maxID, i->source );
maxID = std::max( maxID, i->target );
maxID = std::max( maxID, i->target );
maxEdgeID = std::max( maxEdgeID, i->edgeID );
assert( i->pathLength > 1 );
maxPathLength = std::max( maxPathLength, ( unsigned short ) ( i->pathLength - 2 ) );
nodes.push_back( i->source );
nodes.push_back( i->target );
}
std::sort( nodes.begin(), nodes.end() );
nodes.resize( std::unique( nodes.begin(), nodes.end() ) - nodes.begin() );
const char xBits = bits_needed( max.x - min.x );
const char yBits = bits_needed( max.y - min.y );
const char idBits = bits_needed( maxID - minID );
const char edgeIDBits = bits_needed( maxEdgeID );
const char pathLengthBits = bits_needed( maxPathLength );
int offset = 0;
write_unaligned_unsigned( &buffer, edges.size(), 32, &offset );
write_unaligned_unsigned( &buffer, minID, 32, &offset );
write_unaligned_unsigned( &buffer, idBits, 6, &offset );
write_unaligned_unsigned( &buffer, edgeIDBits, 6, &offset );
write_unaligned_unsigned( &buffer, pathLengthBits, 6, &offset );
NodeID lastTarget = std::numeric_limits< NodeID >::max();
std::vector< UnsignedCoordinate > wayBuffer;
for ( std::vector< Edge >::const_iterator i = edges.begin(), e = edges.end(); i != e; i++ ) {
bool reuse = lastTarget == i->source;
write_unaligned_unsigned( &buffer, reuse ? 1 : 0, 1, &offset );
if ( !reuse )
write_unaligned_unsigned( &buffer, i->source - minID, idBits, &offset );
write_unaligned_unsigned( &buffer, i->target - minID, idBits, &offset );
write_unaligned_unsigned( &buffer, i->edgeID, edgeIDBits, &offset );
write_unaligned_unsigned( &buffer, i->bidirectional ? 1 : 0, 1, &offset );
write_unaligned_unsigned( &buffer, i->pathLength - 2, pathLengthBits, &offset );
assert( i->pathLength >= 2 );
for ( int pathID = 1; pathID < i->pathLength - 1; pathID++ )
wayBuffer.push_back( coordinates[pathID + i->pathID] );
lastTarget = i->target;
}
std::vector< UnsignedCoordinate > nodeCoordinates( nodes.size() );
for ( std::vector< Edge >::iterator i = edges.begin(), e = edges.end(); i != e; ++i ) {
unsigned sourcePos = lower_bound( nodes.begin(), nodes.end(), i->source ) - nodes.begin();
unsigned targetPos = lower_bound( nodes.begin(), nodes.end(), i->target ) - nodes.begin();
nodeCoordinates[sourcePos] = coordinates[i->pathID];
nodeCoordinates[targetPos] = coordinates[i->pathID + i->pathLength - 1];
}
for ( std::vector< UnsignedCoordinate >::const_iterator i = nodeCoordinates.begin(), iend = nodeCoordinates.end(); i != iend; i++ ) {
writeCoordinate( &buffer, &offset, i->x, min.x, max.x, xBits);
writeCoordinate( &buffer, &offset, i->y, min.y, max.y, yBits);
}
for ( std::vector< UnsignedCoordinate >::const_iterator i = wayBuffer.begin(), iend = wayBuffer.end(); i != iend; i++ ) {
writeCoordinate( &buffer, &offset, i->x, min.x, max.x, xBits);
writeCoordinate( &buffer, &offset, i->y, min.y, max.y, yBits);
}
buffer += ( offset + 7 ) / 8;
return buffer - oldBuffer;
}
size_t read( const unsigned char* buffer, UnsignedCoordinate min, UnsignedCoordinate max ) {
const unsigned char* oldBuffer = buffer;
int offset = 0;
const char xBits = bits_needed( max.x - min.x );
const char yBits = bits_needed( max.y - min.y );
unsigned numEdges = read_unaligned_unsigned( &buffer, 32, &offset );
unsigned minID = read_unaligned_unsigned( &buffer, 32, &offset );
unsigned idBits = read_unaligned_unsigned( &buffer, 6, &offset );
unsigned edgeIDBits = read_unaligned_unsigned( &buffer, 6, &offset );
unsigned pathLengthBits = read_unaligned_unsigned( &buffer, 6, &offset );
std::vector< NodeID > nodes;
NodeID lastTarget = std::numeric_limits< NodeID >::max();
for ( unsigned i = 0; i < numEdges; i++ ) {
Edge edge;
bool reuse = read_unaligned_unsigned( &buffer, 1, &offset ) == 1;
if ( reuse )
edge.source = lastTarget;
else
edge.source = read_unaligned_unsigned( &buffer, idBits, &offset ) + minID;
edge.target = read_unaligned_unsigned( &buffer, idBits, &offset ) + minID;
edge.edgeID = read_unaligned_unsigned( &buffer, edgeIDBits, &offset );
edge.bidirectional = read_unaligned_unsigned( &buffer, 1, &offset ) == 1;
edge.pathLength = read_unaligned_unsigned( &buffer, pathLengthBits, &offset );
edges.push_back( edge );
nodes.push_back( edge.source );
nodes.push_back( edge.target );
lastTarget = edge.target;
}
assert( edges.size() != 0 );
std::sort( nodes.begin(), nodes.end() );
nodes.resize( std::unique( nodes.begin(), nodes.end() ) - nodes.begin() );
std::vector< UnsignedCoordinate > nodeCoordinates( nodes.size() );
for ( std::vector< UnsignedCoordinate >::iterator i = nodeCoordinates.begin(), iend = nodeCoordinates.end(); i != iend; i++ ) {
readCoordinate( &buffer, &offset, &i->x, min.x, max.x, xBits);
readCoordinate( &buffer, &offset, &i->y, min.y, max.y, yBits);
}
for ( std::vector< Edge >::iterator i = edges.begin(), iend = edges.end(); i != iend; i++ ) {
unsigned sourcePos = lower_bound( nodes.begin(), nodes.end(), i->source ) - nodes.begin();
unsigned targetPos = lower_bound( nodes.begin(), nodes.end(), i->target ) - nodes.begin();
if ( coordinates.size() == 0 || coordinates.back().x != nodeCoordinates[sourcePos].x || coordinates.back().y != nodeCoordinates[sourcePos].y )
coordinates.push_back( nodeCoordinates[sourcePos] );
i->pathID = coordinates.size() - 1;
for ( int path = 0; path < i->pathLength; path++ ) {
UnsignedCoordinate coordinate;
readCoordinate( &buffer, &offset, &coordinate.x, min.x, max.x, xBits);
readCoordinate( &buffer, &offset, &coordinate.y, min.y, max.y, yBits);
coordinates.push_back( coordinate );
}
coordinates.push_back( nodeCoordinates[targetPos] );
i->pathLength += 2;
}
buffer += ( offset + 7 ) / 8;
return buffer - oldBuffer;
}
protected:
void writeCoordinate( unsigned char** buffer, int* offset, unsigned value, unsigned min, unsigned max, char bits )
{
bool inside = !( value < min || value > max );
write_unaligned_unsigned( buffer, inside ? 1 : 0, 1, offset );
if ( inside )
write_unaligned_unsigned( buffer, value - min, bits, offset );
else
write_unaligned_unsigned( buffer, value, 32, offset );
}
void readCoordinate( const unsigned char** buffer, int* offset, unsigned* value, unsigned min, unsigned /*max*/, char bits )
{
bool inside = read_unaligned_unsigned( buffer, 1, offset ) == 1;
if ( inside )
*value = read_unaligned_unsigned( buffer, bits, offset ) + min;
else
*value = read_unaligned_unsigned( buffer, 32, offset );
}
};
}
#endif // CELL_H