LifePlay-Revival/Plugins/StreetMap/Source/StreetMapImporting/OSMFile.cpp

478 lines
13 KiB
C++
Raw Normal View History

2017-12-09 16:33:11 +00:00
// Copyright 2017 Mike Fricker. All Rights Reserved.
#include "StreetMapImporting.h"
#include "OSMFile.h"
FOSMFile::FOSMFile()
: ParsingState( ParsingState::Root )
{
}
FOSMFile::~FOSMFile()
{
// Clean up time
{
for( auto* Way : Ways )
{
delete Way;
}
Ways.Empty();
for( auto HashPair : NodeMap )
{
FOSMNodeInfo* NodeInfo = HashPair.Value;
delete NodeInfo;
}
NodeMap.Empty();
}
}
bool FOSMFile::LoadOpenStreetMapFile( FString& OSMFilePath, const bool bIsFilePathActuallyTextBuffer, FFeedbackContext* FeedbackContext )
{
const bool bShowSlowTaskDialog = true;
const bool bShowCancelButton = true;
FText ErrorMessage;
int32 ErrorLineNumber;
if( FFastXml::ParseXmlFile(
this,
bIsFilePathActuallyTextBuffer ? nullptr : *OSMFilePath,
bIsFilePathActuallyTextBuffer ? OSMFilePath.GetCharArray().GetData() : nullptr,
FeedbackContext,
bShowSlowTaskDialog,
bShowCancelButton,
/* Out */ ErrorMessage,
/* Out */ ErrorLineNumber ) )
{
if( NodeMap.Num() > 0 )
{
AverageLatitude /= NodeMap.Num();
AverageLongitude /= NodeMap.Num();
}
return true;
}
if( FeedbackContext != nullptr )
{
FeedbackContext->Logf(
ELogVerbosity::Error,
TEXT( "Failed to load OpenStreetMap XML file ('%s', Line %i)" ),
*ErrorMessage.ToString(),
ErrorLineNumber );
}
return false;
}
bool FOSMFile::ProcessXmlDeclaration( const TCHAR* ElementData, int32 XmlFileLineNumber )
{
// Don't care about XML declaration
return true;
}
bool FOSMFile::ProcessComment( const TCHAR* Comment )
{
// Don't care about comments
return true;
}
bool FOSMFile::ProcessElement( const TCHAR* ElementName, const TCHAR* ElementData, int32 XmlFileLineNumber )
{
if( ParsingState == ParsingState::Root )
{
if( !FCString::Stricmp( ElementName, TEXT( "node" ) ) )
{
ParsingState = ParsingState::Node;
CurrentNodeInfo = new FOSMNodeInfo();
CurrentNodeInfo->Latitude = 0.0;
CurrentNodeInfo->Longitude = 0.0;
}
else if( !FCString::Stricmp( ElementName, TEXT( "way" ) ) )
{
ParsingState = ParsingState::Way;
CurrentWayInfo = new FOSMWayInfo();
CurrentWayInfo->Name.Empty();
CurrentWayInfo->Ref.Empty();
CurrentWayInfo->WayType = EOSMWayType::Other;
CurrentWayInfo->Height = 0.0;
CurrentWayInfo->bIsOneWay = false;
// @todo: We're currently ignoring the "visible" tag on ways, which means that roads will always
// be included in our data set. It might be nice to make this an import option.
}
}
else if( ParsingState == ParsingState::Way )
{
if( !FCString::Stricmp( ElementName, TEXT( "nd" ) ) )
{
ParsingState = ParsingState::Way_NodeRef;
}
else if( !FCString::Stricmp( ElementName, TEXT( "tag" ) ) )
{
ParsingState = ParsingState::Way_Tag;
}
}
return true;
}
bool FOSMFile::ProcessAttribute( const TCHAR* AttributeName, const TCHAR* AttributeValue )
{
if( ParsingState == ParsingState::Node )
{
if( !FCString::Stricmp( AttributeName, TEXT( "id" ) ) )
{
CurrentNodeID = FPlatformString::Atoi64( AttributeValue );
}
else if( !FCString::Stricmp( AttributeName, TEXT( "lat" ) ) )
{
CurrentNodeInfo->Latitude = FPlatformString::Atod( AttributeValue );
AverageLatitude += CurrentNodeInfo->Latitude;
// Update minimum and maximum latitude
// @todo: Performance: Instead of computing our own bounding box, we could parse the "minlat" and
// "minlon" tags from the OSM file
if( CurrentNodeInfo->Latitude < MinLatitude )
{
MinLatitude = CurrentNodeInfo->Latitude;
}
if( CurrentNodeInfo->Latitude > MaxLatitude )
{
MaxLatitude = CurrentNodeInfo->Latitude;
}
}
else if( !FCString::Stricmp( AttributeName, TEXT( "lon" ) ) )
{
CurrentNodeInfo->Longitude = FPlatformString::Atod( AttributeValue );
AverageLongitude += CurrentNodeInfo->Longitude;
// Update minimum and maximum longitude
if( CurrentNodeInfo->Longitude < MinLongitude )
{
MinLongitude = CurrentNodeInfo->Longitude;
}
if( CurrentNodeInfo->Longitude > MaxLongitude )
{
MaxLongitude = CurrentNodeInfo->Longitude;
}
}
}
else if( ParsingState == ParsingState::Way )
{
// ...
}
else if( ParsingState == ParsingState::Way_NodeRef )
{
if( !FCString::Stricmp( AttributeName, TEXT( "ref" ) ) )
{
FOSMNodeInfo* ReferencedNode = NodeMap.FindRef( FPlatformString::Atoi64( AttributeValue ) );
const int NewNodeIndex = CurrentWayInfo->Nodes.Num();
CurrentWayInfo->Nodes.Add( ReferencedNode );
// Update the node with information about the way that is referencing it
{
FOSMWayRef NewWayRef;
NewWayRef.Way = CurrentWayInfo;
NewWayRef.NodeIndex = NewNodeIndex;
ReferencedNode->WayRefs.Add( NewWayRef );
}
}
}
else if( ParsingState == ParsingState::Way_Tag )
{
if( !FCString::Stricmp( AttributeName, TEXT( "k" ) ) )
{
CurrentWayTagKey = AttributeValue;
}
else if( !FCString::Stricmp( AttributeName, TEXT( "v" ) ) )
{
if( !FCString::Stricmp( CurrentWayTagKey, TEXT( "name" ) ) )
{
CurrentWayInfo->Name = AttributeValue;
}
else if( !FCString::Stricmp( CurrentWayTagKey, TEXT( "ref" ) ) )
{
CurrentWayInfo->Ref = AttributeValue;
}
else if( !FCString::Stricmp( CurrentWayTagKey, TEXT( "highway" ) ) )
{
EOSMWayType WayType = EOSMWayType::Other;
if( !FCString::Stricmp( AttributeValue, TEXT( "motorway" ) ) )
{
WayType = EOSMWayType::Motorway;
}
else if( !FCString::Stricmp( AttributeValue, TEXT( "motorway_link" ) ) )
{
WayType = EOSMWayType::Motorway_Link;
}
else if( !FCString::Stricmp( AttributeValue, TEXT( "trunk" ) ) )
{
WayType = EOSMWayType::Trunk;
}
else if( !FCString::Stricmp( AttributeValue, TEXT( "trunk_link" ) ) )
{
WayType = EOSMWayType::Trunk_Link;
}
else if( !FCString::Stricmp( AttributeValue, TEXT( "primary" ) ) )
{
WayType = EOSMWayType::Primary;
}
else if( !FCString::Stricmp( AttributeValue, TEXT( "primary_link" ) ) )
{
WayType = EOSMWayType::Primary_Link;
}
else if( !FCString::Stricmp( AttributeValue, TEXT( "secondary" ) ) )
{
WayType = EOSMWayType::Secondary;
}
else if( !FCString::Stricmp( AttributeValue, TEXT( "secondary_link" ) ) )
{
WayType = EOSMWayType::Secondary_Link;
}
else if( !FCString::Stricmp( AttributeValue, TEXT( "tertiary" ) ) )
{
WayType = EOSMWayType::Tertiary;
}
else if( !FCString::Stricmp( AttributeValue, TEXT( "tertiary_link" ) ) )
{
WayType = EOSMWayType::Tertiary_Link;
}
else if( !FCString::Stricmp( AttributeValue, TEXT( "residential" ) ) )
{
WayType = EOSMWayType::Residential;
}
else if( !FCString::Stricmp( AttributeValue, TEXT( "service" ) ) )
{
WayType = EOSMWayType::Service;
}
else if( !FCString::Stricmp( AttributeValue, TEXT( "unclassified" ) ) )
{
WayType = EOSMWayType::Unclassified;
}
else if( !FCString::Stricmp( AttributeValue, TEXT( "living_street" ) ) )
{
WayType = EOSMWayType::Living_Street;
}
else if( !FCString::Stricmp( AttributeValue, TEXT( "pedestrian" ) ) )
{
WayType = EOSMWayType::Pedestrian;
}
else if( !FCString::Stricmp( AttributeValue, TEXT( "track" ) ) )
{
WayType = EOSMWayType::Track;
}
else if( !FCString::Stricmp( AttributeValue, TEXT( "bus_guideway" ) ) )
{
WayType = EOSMWayType::Bus_Guideway;
}
else if( !FCString::Stricmp( AttributeValue, TEXT( "raceway" ) ) )
{
WayType = EOSMWayType::Raceway;
}
else if( !FCString::Stricmp( AttributeValue, TEXT( "road" ) ) )
{
WayType = EOSMWayType::Road;
}
else if( !FCString::Stricmp( AttributeValue, TEXT( "footway" ) ) )
{
WayType = EOSMWayType::Footway;
}
else if( !FCString::Stricmp( AttributeValue, TEXT( "cycleway" ) ) )
{
WayType = EOSMWayType::Cycleway;
}
else if( !FCString::Stricmp( AttributeValue, TEXT( "bridleway" ) ) )
{
WayType = EOSMWayType::Bridleway;
}
else if( !FCString::Stricmp( AttributeValue, TEXT( "steps" ) ) )
{
WayType = EOSMWayType::Steps;
}
else if( !FCString::Stricmp( AttributeValue, TEXT( "path" ) ) )
{
WayType = EOSMWayType::Path;
}
else if( !FCString::Stricmp( AttributeValue, TEXT( "proposed" ) ) )
{
WayType = EOSMWayType::Proposed;
}
else if( !FCString::Stricmp( AttributeValue, TEXT( "construction" ) ) )
{
WayType = EOSMWayType::Construction;
}
else
{
// Other type that we don't recognize yet. See http://wiki.openstreetmap.org/wiki/Key:highway
}
CurrentWayInfo->WayType = WayType;
}
else if( !FCString::Stricmp( CurrentWayTagKey, TEXT( "building" ) ) )
{
CurrentWayInfo->WayType = EOSMWayType::Building;
// Vinfamy added
CurrentWayInfo->Building = AttributeValue;
if( !FCString::Stricmp( AttributeValue, TEXT( "yes" ) ) )
{
CurrentWayInfo->WayType = EOSMWayType::Building;
}
else
{
// Other type that we don't recognize yet. See http://wiki.openstreetmap.org/wiki/Key:building
}
}
2017-12-11 19:33:54 +00:00
/**
else if( !FCString::Stricmp( CurrentWayTagKey, TEXT( "natural" ) ) )
{
if( !FCString::Stricmp( AttributeValue, TEXT( "water" ) ) )
{
CurrentWayInfo->WayType = EOSMWayType::Water;
}
else
{
// Other natural type that we don't recognize yet. See http://wiki.openstreetmap.org/wiki/Key:building
}
}
else if( !FCString::Stricmp( CurrentWayTagKey, TEXT( "waterway" ) ) )
{
CurrentWayInfo->WayType = EOSMWayType::Water;
}
else if( !FCString::Stricmp( CurrentWayTagKey, TEXT( "water" ) ) )
{
CurrentWayInfo->WayType = EOSMWayType::Water;
}
else if( !FCString::Stricmp( CurrentWayTagKey, TEXT( "landuse" ) ) )
{
if( !FCString::Stricmp( AttributeValue, TEXT( "basin" ) ) )
{
CurrentWayInfo->WayType = EOSMWayType::Water;
}
else if( !FCString::Stricmp( AttributeValue, TEXT( "reservoir" ) ) )
{
CurrentWayInfo->WayType = EOSMWayType::Water;
}
else if( !FCString::Stricmp( AttributeValue, TEXT( "pond" ) ) )
{
CurrentWayInfo->WayType = EOSMWayType::Water;
}
}
*/
else if( !FCString::Stricmp( CurrentWayTagKey, TEXT( "leisure" ) ) )
{
if( !FCString::Stricmp( AttributeValue, TEXT( "park" ) ) )
{
CurrentWayInfo->WayType = EOSMWayType::Park;
}
else if( !FCString::Stricmp( AttributeValue, TEXT( "fitness_centre" ) ) )
{
CurrentWayInfo->WayType = EOSMWayType::Building;
CurrentWayInfo->Amenity = AttributeValue;
}
else
{
// Other natural type that we don't recognize yet. See http://wiki.openstreetmap.org/wiki/Key:building
}
}
2017-12-09 16:33:11 +00:00
else if( !FCString::Stricmp( CurrentWayTagKey, TEXT( "height" ) ) )
{
// Check to see if there is a space character in the height value. For now, we're looking
// for straight-up floating point values.
if( !FString( AttributeValue ).Contains( TEXT( " " ) ) )
{
// Okay, no space character. So this has got to be a floating point number. The OSM
// spec says that the height values are in meters.
CurrentWayInfo->Height = FPlatformString::Atod( AttributeValue );
}
else
{
// Looks like the height value contains units of some sort.
// @todo: Add support for interpreting unit strings and converting the values
}
}
else if (!FCString::Stricmp(CurrentWayTagKey, TEXT("building:levels")))
{
CurrentWayInfo->BuildingLevels = FPlatformString::Atoi(AttributeValue);
}
// Vinfamy added
else if (!FCString::Stricmp(CurrentWayTagKey, TEXT("amenity")))
{
CurrentWayInfo->Amenity = AttributeValue;
}
else if( !FCString::Stricmp( CurrentWayTagKey, TEXT( "oneway" ) ) )
{
if( !FCString::Stricmp( AttributeValue, TEXT( "yes" ) ) )
{
CurrentWayInfo->bIsOneWay = true;
}
else
{
CurrentWayInfo->bIsOneWay = false;
}
}
}
}
return true;
}
bool FOSMFile::ProcessClose( const TCHAR* Element )
{
if( ParsingState == ParsingState::Node )
{
NodeMap.Add( CurrentNodeID, CurrentNodeInfo );
CurrentNodeID = 0;
CurrentNodeInfo = nullptr;
ParsingState = ParsingState::Root;
}
else if( ParsingState == ParsingState::Way )
{
Ways.Add( CurrentWayInfo );
CurrentWayInfo = nullptr;
ParsingState = ParsingState::Root;
}
else if( ParsingState == ParsingState::Way_NodeRef )
{
ParsingState = ParsingState::Way;
}
else if( ParsingState == ParsingState::Way_Tag )
{
CurrentWayTagKey = TEXT( "" );
ParsingState = ParsingState::Way;
}
return true;
}