routino-3.4.3/ 40755 233 144 0 15003125373 6353 5 routino-3.4.3/src/ 40755 233 144 0 15003125373 7142 5 routino-3.4.3/src/planetsplitter.c 644 233 144 55767 14774247216 12457 0 /***************************************
OSM planet file splitter.
Part of the Routino routing software.
******************/ /******************
This file Copyright 2008-2017, 2023, 2025 Andrew M. Bishop
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program 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 Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see .
***************************************/
#include
#include
#include
#include
#include "version.h"
#include "types.h"
#include "ways.h"
#include "typesx.h"
#include "nodesx.h"
#include "segmentsx.h"
#include "waysx.h"
#include "relationsx.h"
#include "superx.h"
#include "prunex.h"
#include "files.h"
#include "logging.h"
#include "errorlogx.h"
#include "functions.h"
#include "osmparser.h"
#include "tagging.h"
#include "uncompress.h"
/* Global variables */
/*+ The name of the temporary directory. +*/
char *option_tmpdirname=NULL;
/*+ The amount of RAM to use for filesorting. +*/
ssize_t option_filesort_ramsize=0;
/*+ The number of threads to use for filesorting. +*/
int option_filesort_threads=1;
/* Local functions */
static void print_usage(int detail,const char *argerr,const char *err);
/*++++++++++++++++++++++++++++++++++++++
The main program for the planetsplitter.
++++++++++++++++++++++++++++++++++++++*/
int main(int argc,char** argv)
{
NodesX *OSMNodes;
SegmentsX *OSMSegments,*SuperSegments=NULL,*MergedSegments=NULL;
WaysX *OSMWays;
RelationsX *OSMRelations;
int iteration=0,quit=0;
int max_iterations=5;
char *dirname=NULL,*prefix=NULL,*tagging=NULL,*errorlog=NULL;
int option_parse_only=0,option_process_only=0;
int option_append=0,option_keep=0,option_changes=0;
int option_filenames=0;
int option_prune_isolated=500,option_prune_short=5,option_prune_straight=3;
int arg;
printf_program_start();
/* Parse the command line arguments */
for(arg=1;arg1024*1024)
print_usage(0,NULL,"Sorting RAM size '--sort-ram-size=...' must be positive and in MB.");
else if(option_filesort_ramsize==0)
{
#if SLIM
option_filesort_ramsize=256*1024*1024;
#else
option_filesort_ramsize=1024*1024*1024;
#endif
}
else
option_filesort_ramsize*=1024*1024;
#if defined(USE_PTHREADS) && USE_PTHREADS
if(option_filesort_threads<1 || option_filesort_threads>32)
print_usage(0,NULL,"Sorting threads '--sort-threads=...' must be small positive integer.");
#endif
if(!option_tmpdirname)
{
if(!dirname)
option_tmpdirname=".";
else
option_tmpdirname=dirname;
}
if(!option_process_only)
{
if(tagging)
{
if(!ExistsFile(tagging))
{
fprintf(stderr,"Error: The '--tagging' option specifies a file '%s' that does not exist.\n",tagging);
exit(EXIT_FAILURE);
}
}
else
{
tagging=FileName(dirname,prefix,"tagging.xml");
if(!ExistsFile(tagging))
{
char *defaulttagging=FileName(ROUTINO_DATADIR,NULL,"tagging.xml");
if(!ExistsFile(defaulttagging))
{
fprintf(stderr,"Error: The '--tagging' option was not used and the files '%s' and '%s' do not exist.\n",tagging,defaulttagging);
exit(EXIT_FAILURE);
}
free(tagging);
tagging=defaulttagging;
}
}
if(ParseXMLTaggingRules(tagging))
{
fprintf(stderr,"Error: Cannot read the tagging rules in the file '%s'.\n",tagging);
exit(EXIT_FAILURE);
}
}
/* Create new node, segment, way and relation variables */
OSMNodes=NewNodeList(option_append||option_changes,option_process_only);
OSMWays=NewWayList(option_append||option_changes,option_process_only);
OSMRelations=NewRelationList(option_append||option_changes,option_process_only);
/* Create the error log file */
if(errorlog)
open_errorlog(FileName(dirname,prefix,errorlog),option_append||option_changes||option_process_only,option_keep);
/* Parse the file */
if(!option_process_only)
{
for(arg=1;arg9?"=":"");
fflush(stdout);
if(iteration==0)
{
/* Select the super-nodes */
ChooseSuperNodes(OSMNodes,OSMSegments,OSMWays);
/* Select the super-segments */
SuperSegments=CreateSuperSegments(OSMNodes,OSMSegments,OSMWays);
nsuper=OSMSegments->number;
}
else
{
SegmentsX *SuperSegments2;
/* Index the super-segments */
IndexSegments(SuperSegments,OSMNodes,OSMWays);
/* Select the super-nodes */
ChooseSuperNodes(OSMNodes,SuperSegments,OSMWays);
/* Select the super-segments */
SuperSegments2=CreateSuperSegments(OSMNodes,SuperSegments,OSMWays);
nsuper=SuperSegments->number;
FreeSegmentList(SuperSegments);
SuperSegments=SuperSegments2;
}
/* Sort the super-segments and remove duplicates */
DeduplicateSuperSegments(SuperSegments,OSMWays);
/* Check for end condition */
if(SuperSegments->number==nsuper)
quit=1;
iteration++;
if(iteration>max_iterations)
quit=1;
}
while(!quit);
/* Combine the super-segments */
printf("\nCombine Segments and Super-Segments\n===================================\n\n");
fflush(stdout);
/* Merge the super-segments */
MergedSegments=MergeSuperSegments(OSMSegments,SuperSegments);
FreeSegmentList(OSMSegments);
FreeSegmentList(SuperSegments);
OSMSegments=MergedSegments;
/* Cross reference the nodes and segments */
printf("\nCross-Reference Nodes and Segments\n==================================\n\n");
fflush(stdout);
/* Sort the nodes and segments geographically */
SortNodeListGeographically(OSMNodes);
SortSegmentListGeographically(OSMSegments,OSMNodes);
/* Re-index the segments */
IndexSegments(OSMSegments,OSMNodes,OSMWays);
/* Sort the turn relations geographically */
SortTurnRelationListGeographically(OSMRelations,OSMNodes,OSMSegments,1);
/* Output the results */
printf("\nWrite Out Database Files\n========================\n\n");
fflush(stdout);
/* Write out the nodes */
SaveNodeList(OSMNodes,FileName(dirname,prefix,"nodes.mem"),OSMSegments);
/* Write out the segments */
SaveSegmentList(OSMSegments,FileName(dirname,prefix,"segments.mem"));
/* Write out the ways */
SaveWayList(OSMWays,FileName(dirname,prefix,"ways.mem"));
/* Write out the relations */
SaveRelationList(OSMRelations,FileName(dirname,prefix,"relations.mem"));
/* Free the memory (delete the temporary files) */
FreeSegmentList(OSMSegments);
/* Close the error log file and process the data */
if(errorlog)
{
close_errorlog();
if(option_keep)
{
ErrorLogsX *OSMErrorLogs;
printf("\nCreate Error Log\n================\n\n");
fflush(stdout);
OSMErrorLogs=NewErrorLogList();
ProcessErrorLogs(OSMErrorLogs,OSMNodes,OSMWays,OSMRelations);
SortErrorLogsGeographically(OSMErrorLogs);
SaveErrorLogs(OSMErrorLogs,FileName(dirname,prefix,"errorlogs.mem"));
FreeErrorLogList(OSMErrorLogs);
}
}
/* Free the memory (delete the temporary files) */
FreeNodeList(OSMNodes,0);
FreeWayList(OSMWays,0);
FreeRelationList(OSMRelations,0);
printf("\n");
fflush(stdout);
printf_program_end();
exit(EXIT_SUCCESS);
}
/*++++++++++++++++++++++++++++++++++++++
Print out the usage information.
int detail The level of detail to use: -1 = just version number, 0 = low detail, 1 = full details.
const char *argerr The argument that gave the error (if there is one).
const char *err Other error message (if there is one).
++++++++++++++++++++++++++++++++++++++*/
static void print_usage(int detail,const char *argerr,const char *err)
{
if(detail<0)
{
fprintf(stderr,
"Routino version " ROUTINO_VERSION " " ROUTINO_URL ".\n"
);
}
if(detail>=0)
{
fprintf(stderr,
"Usage: planetsplitter [--version]\n"
" [--help]\n"
" [--dir=] [--prefix=]\n"
#if defined(USE_PTHREADS) && USE_PTHREADS
" [--sort-ram-size=] [--sort-threads=]\n"
#else
" [--sort-ram-size=]\n"
#endif
" [--tmpdir=]\n"
" [--tagging=]\n"
" [--loggable] [--logtime] [--logmemory]\n"
" [--errorlog[=]]\n"
" [--parse-only | --process-only]\n"
" [--append] [--keep] [--changes]\n"
" [--max-iterations=]\n"
" [--prune-none]\n"
" [--prune-isolated=]\n"
" [--prune-short=]\n"
" [--prune-straight=]\n"
" [ ... | ...\n"
" | ...\n"
" | ... | ..."
#if defined(USE_BZIP2) && USE_BZIP2
"\n | ..."
#endif
#if defined(USE_GZIP) && USE_GZIP
"\n | ..."
#endif
#if defined(USE_XZ) && USE_XZ
"\n | ..."
#endif
"]\n");
if(argerr)
fprintf(stderr,
"\n"
"Error with command line parameter: %s\n",argerr);
if(err)
fprintf(stderr,
"\n"
"Error: %s\n",err);
}
if(detail==1)
fprintf(stderr,
"\n"
"--version Print the version of Routino.\n"
"\n"
"--help Prints this information.\n"
"\n"
"--dir= The directory containing the routing database.\n"
"--prefix= The filename prefix for the routing database.\n"
"\n"
"--sort-ram-size= The amount of RAM (in MB) to use for data sorting\n"
#if SLIM
" (defaults to 256MB otherwise.)\n"
#else
" (defaults to 1024MB otherwise.)\n"
#endif
#if defined(USE_PTHREADS) && USE_PTHREADS
"--sort-threads= The number of threads to use for data sorting.\n"
#endif
"\n"
"--tmpdir= The directory name for temporary files.\n"
" (defaults to the '--dir' option directory.)\n"
"\n"
"--tagging= The name of the XML file containing the tagging rules\n"
" (defaults to 'tagging.xml' with '--dir' and\n"
" '--prefix' options or the file installed in\n"
" '" ROUTINO_DATADIR "').\n"
"\n"
"--loggable Print progress messages suitable for logging to file.\n"
"--logtime Print the elapsed time for each processing step.\n"
"--logmemory Print the max allocated/mapped memory for each step.\n"
"--errorlog[=] Log parsing errors to 'error.log' or the given name\n"
" (the '--dir' and '--prefix' options are applied).\n"
"\n"
"--parse-only Parse the OSM/OSC file(s) and store the results.\n"
"--process-only Process the stored results from previous option.\n"
"--append Parse the OSM file(s) and append to existing results.\n"
"--keep Keep the intermediate files after parsing & sorting.\n"
"--changes Parse the data as an OSC file and apply the changes.\n"
"\n"
"--max-iterations= The number of iterations for finding super-nodes\n"
" (defaults to 5).\n"
"\n"
"--prune-none Disable the prune options below, they are re-enabled\n"
" by adding them to the command line after this option.\n"
"--prune-isolated= Remove access from small disconnected segment groups\n"
" (defaults to removing groups under 500m).\n"
"--prune-short= Remove short segments (defaults to removing segments\n"
" up to a maximum length of 5m).\n"
"--prune-straight= Remove nodes in almost straight highways (defaults to\n"
" removing nodes up to 3m offset from a straight line).\n"
"\n"
", , , , \n"
" The name(s) of the file(s) to read and parse.\n"
" Filenames ending '.pbf' read as PBF, filenames ending\n"
" '.o5m' or '.o5c' read as O5M/O5C, others as XML.\n"
#if defined(USE_BZIP2) && USE_BZIP2
" Filenames ending '.bz2' will be bzip2 uncompressed.\n"
#endif
#if defined(USE_GZIP) && USE_GZIP
" Filenames ending '.gz' will be gzip uncompressed.\n"
#endif
#if defined(USE_XZ) && USE_XZ
" Filenames ending '.xz' will be xz uncompressed.\n"
#endif
"\n"
" defaults to all but can be set to:\n"
"%s"
"\n"
" can be selected from:\n"
"%s"
"\n"
" can be selected from:\n"
"%s",
TransportList(),HighwayList(),PropertyList());
exit(!detail);
}
routino-3.4.3/src/types.h 644 233 144 34411 14672572020 10524 0 /***************************************
Type definitions
Part of the Routino routing software.
******************/ /******************
This file Copyright 2008-2014, 2019 Andrew M. Bishop
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program 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 Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see .
***************************************/
#ifndef TYPES_H
#define TYPES_H /*+ To stop multiple inclusions. +*/
#include
#include
#include
#ifndef M_PI
#define M_PI 3.14159265358979323846
#endif
/* Constants and macros for handling them */
/*+ The number of waypoints allowed to be specified. +*/
#define NWAYPOINTS 99
/*+ An undefined waypoint index. +*/
#define NO_WAYPOINT ((waypoint_t)~0)
/*+ An undefined node index. +*/
#define NO_NODE ((index_t)~0)
/*+ An undefined segment index. +*/
#define NO_SEGMENT ((index_t)~0)
/*+ An undefined way index. +*/
#define NO_WAY ((index_t)~0)
/*+ An undefined relation index. +*/
#define NO_RELATION ((index_t)~0)
/*+ An undefined location. +*/
#define NO_LATLONG ((latlong_t)0x80000000)
/*+ The lowest number allowed for a fake node (allows 65535 of them). +*/
#define NODE_FAKE (((index_t)~0)<<16)
/*+ The lowest number allowed for a fake segment (allows 65535 of them). +*/
#define SEGMENT_FAKE (((index_t)~0)<<16)
/*+ The latitude and longitude conversion factor from floating point (radians) to integer. +*/
#define LAT_LONG_SCALE (1024*65536)
/*+ The latitude and longitude integer range within each bin. +*/
#define LAT_LONG_BIN 65536
/*+ A flag to mark a node as a super-node. +*/
#define NODE_SUPER ((nodeflags_t)0x8000)
/*+ A flag to mark a node as suitable for a U-turn. +*/
#define NODE_UTURN ((nodeflags_t)0x4000)
/*+ A flag to mark a node as a mini-roundabout. +*/
#define NODE_MINIRNDBT ((nodeflags_t)0x2000)
/*+ A flag to mark a node as a turn relation via node. +*/
#define NODE_TURNRSTRCT ((nodeflags_t)0x1000)
/*+ A flag to mark a node as adjacent to a turn relation via node. +*/
#define NODE_TURNRSTRCT2 ((nodeflags_t)0x0800)
/*+ A flag to mark a node as deleted. +*/
#define NODE_DELETED ((nodeflags_t)0x0400)
/*+ A flag to mark a segment as being part of an area (must be the highest valued flag). +*/
#define SEGMENT_AREA ((distance_t)0x80000000)
/*+ A flag to mark a segment as one-way from node1 to node2. +*/
#define ONEWAY_1TO2 ((distance_t)0x40000000)
/*+ A flag to mark a segment as one-way from node2 to node1. +*/
#define ONEWAY_2TO1 ((distance_t)0x20000000)
/*+ A flag to mark a segment as a super-segment. +*/
#define SEGMENT_SUPER ((distance_t)0x10000000)
/*+ A flag to mark a segment as a normal segment. +*/
#define SEGMENT_NORMAL ((distance_t)0x08000000)
/*+ The real distance ignoring the other flags. +*/
#define DISTANCE(xx) ((distance_t)((xx)&(~(SEGMENT_AREA|ONEWAY_1TO2|ONEWAY_2TO1|SEGMENT_SUPER|SEGMENT_NORMAL))))
/*+ The distance flags selecting only the flags. +*/
#define DISTFLAG(xx) ((distance_t)((xx)&(SEGMENT_AREA|ONEWAY_1TO2|ONEWAY_2TO1|SEGMENT_SUPER|SEGMENT_NORMAL)))
/*+ A very large almost infinite distance. +*/
#define INF_DISTANCE DISTANCE(~0)
/*+ A very large almost infinite score. +*/
#define INF_SCORE (score_t)1E30
/*+ A flag to mark a deleted way. +*/
#define WAY_DELETED ((highway_t)~0)
/*+ A flag to mark a deleted relation. +*/
#define RELATION_DELETED ((transports_t)~0)
/* Simple Types */
/*+ A waypoint index. +*/
typedef uint16_t waypoint_t;
/*+ A node, segment, way or relation index. +*/
typedef uint32_t index_t;
/*+ A printf formatting string for an index_t type (this should match the index_t definition above). +*/
#define Pindex_t PRIu32 /* PRIu32 and PRIu64 are defined in intypes.h */
/*+ A node latitude or longitude (range: +/-pi*LAT_LONG_SCALE = +/-3.14*1024*65536 = ~29 bits). +*/
typedef int32_t latlong_t;
/*+ A node latitude or longitude bin number (range: +/-pi*LAT_LONG_SCALE/LAT_LONG_BIN = +/-3.14*1024 = ~13 bits). +*/
typedef int16_t ll_bin_t;
/*+ A node latitude and longitude bin number (range: +/-(pi*LAT_LONG_SCALE/LAT_LONG_BIN)^2 = +/-(3.14*1024)^2 = ~26 bits). +*/
typedef int32_t ll_bin2_t;
/*+ A node latitude or longitude offset (range: 0 -> LAT_LONG_BIN-1 = 0 -> 65535 = 16 bits). +*/
typedef uint16_t ll_off_t;
/*+ Conversion from a latlong (integer latitude or longitude) to a bin number. +*/
#define latlong_to_bin(xxx) (ll_bin_t)((latlong_t)((xxx)&~(LAT_LONG_BIN-1))/LAT_LONG_BIN)
/*+ Conversion from a bin number to a latlong (integer latitude or longitude). +*/
#define bin_to_latlong(xxx) ((latlong_t)(xxx)*LAT_LONG_BIN)
/*+ Conversion from a latlong (integer latitude or longitude) to a bin offset. +*/
#define latlong_to_off(xxx) (ll_off_t)((latlong_t)(xxx)&(LAT_LONG_BIN-1))
/*+ Conversion from a bin offset to a latlong (integer latitude or longitude). +*/
#define off_to_latlong(xxx) ((latlong_t)(xxx))
/*+ Conversion from a latitude or longitude in radians to a latlong (integer latitude or longitude). +*/
#define radians_to_latlong(xxx) ((latlong_t)floor((xxx)*LAT_LONG_SCALE+0.5))
/*+ Conversion from a latlong (integer latitude or longitude) to a latitude or longitude in radians. +*/
#define latlong_to_radians(xxx) ((double)(xxx)/LAT_LONG_SCALE)
/*+ Conversion from radians to degrees. +*/
#define radians_to_degrees(xxx) ((xxx)*(180.0/M_PI))
/*+ Conversion from degrees to radians. +*/
#define degrees_to_radians(xxx) ((xxx)*(M_PI/180.0))
/*+ Node flags. +*/
typedef uint16_t nodeflags_t;
/*+ A distance, measured in metres (will not overflow for any earth-based distance). +*/
typedef uint32_t distance_t;
/*+ A duration, measured in 1/10th seconds (will not overflow for 13 years). +*/
typedef uint32_t duration_t;
/*+ A routing optimisation score. +*/
typedef float score_t;
/*+ Conversion from distance_t to kilometres. +*/
#define distance_to_km(xx) ((double)(xx)/1000.0)
/*+ Conversion from kilometres to distance_t. +*/
#define km_to_distance(xx) ((distance_t)((double)(xx)*1000.0))
/*+ Conversion from duration_t to minutes. +*/
#define duration_to_minutes(xx) ((double)(xx)/600.0)
/*+ Conversion from duration_t to hours. +*/
#define duration_to_hours(xx) ((double)(xx)/36000.0)
/*+ Conversion from hours to duration_t. +*/
#define hours_to_duration(xx) ((duration_t)((double)(xx)*36000.0))
/*+ Conversion from distance_t and speed_t to duration_t. +*/
#define distance_speed_to_duration(xx,yy) ((duration_t)(((double)(xx)/(double)(yy))*(36000.0/1000.0)))
/*+ The type of a highway. +*/
typedef uint8_t highway_t;
/*+ The different types of a highway. +*/
typedef enum _Highway
{
Highway_None = 0,
Highway_Motorway = 1,
Highway_Trunk = 2,
Highway_Primary = 3,
Highway_Secondary = 4,
Highway_Tertiary = 5,
Highway_Unclassified = 6,
Highway_Residential = 7,
Highway_Service = 8,
Highway_Track = 9,
Highway_Cycleway = 10,
Highway_Path = 11,
Highway_Steps = 12,
Highway_Ferry = 13,
Highway_Count = 14, /* One more than the number of highway types. */
Highway_CycleBothWays = 16,
Highway_OneWay = 32,
Highway_Roundabout = 64,
Highway_Area = 128
}
Highway;
#define HIGHWAY(xx) ((xx)&0x0f)
/*+ A bitmask of multiple highway types. +*/
typedef uint16_t highways_t;
#define HIGHWAYS(xx) (1<<(HIGHWAY(xx)-1))
/*+ The different types of a highway as a bitmask. +*/
typedef enum _Highways
{
Highways_None = 0,
Highways_Motorway = HIGHWAYS(Highway_Motorway ),
Highways_Trunk = HIGHWAYS(Highway_Trunk ),
Highways_Primary = HIGHWAYS(Highway_Primary ),
Highways_Secondary = HIGHWAYS(Highway_Secondary ),
Highways_Tertiary = HIGHWAYS(Highway_Tertiary ),
Highways_Unclassified = HIGHWAYS(Highway_Unclassified),
Highways_Residential = HIGHWAYS(Highway_Residential ),
Highways_Service = HIGHWAYS(Highway_Service ),
Highways_Track = HIGHWAYS(Highway_Track ),
Highways_Cycleway = HIGHWAYS(Highway_Cycleway ),
Highways_Path = HIGHWAYS(Highway_Path ),
Highways_Steps = HIGHWAYS(Highway_Steps ),
Highways_Ferry = HIGHWAYS(Highway_Ferry )
}
Highways;
/*+ The type of a transport. +*/
typedef uint8_t transport_t;
/*+ The different types of transport. +*/
typedef enum _Transport
{
Transport_None = 0,
Transport_Foot = 1,
Transport_Horse = 2,
Transport_Wheelchair = 3,
Transport_Bicycle = 4,
Transport_Moped = 5,
Transport_Motorcycle = 6,
Transport_Motorcar = 7,
Transport_Goods = 8,
Transport_HGV = 9,
Transport_PSV = 10,
Transport_Count = 11 /*+ One more than the number of transport types. +*/
}
Transport;
/*+ A bitmask of multiple transport types. +*/
typedef uint16_t transports_t;
#define TRANSPORTS(xx) (1<<((xx)-1))
/*+ The different types of transport as a bitmask. +*/
typedef enum _Transports
{
Transports_None = 0,
Transports_Foot = TRANSPORTS(Transport_Foot ),
Transports_Horse = TRANSPORTS(Transport_Horse ),
Transports_Wheelchair = TRANSPORTS(Transport_Wheelchair),
Transports_Bicycle = TRANSPORTS(Transport_Bicycle ),
Transports_Moped = TRANSPORTS(Transport_Moped ),
Transports_Motorcycle = TRANSPORTS(Transport_Motorcycle),
Transports_Motorcar = TRANSPORTS(Transport_Motorcar ),
Transports_Goods = TRANSPORTS(Transport_Goods ),
Transports_HGV = TRANSPORTS(Transport_HGV ),
Transports_PSV = TRANSPORTS(Transport_PSV ),
Transports_ALL = TRANSPORTS(Transport_Count )-1
}
Transports;
/*+ The type of a property. +*/
typedef uint8_t property_t;
/*+ The different types of property. +*/
typedef enum _Property
{
Property_None = 0,
Property_Paved = 1,
Property_Multilane = 2,
Property_Bridge = 3,
Property_Tunnel = 4,
Property_FootRoute = 5,
Property_BicycleRoute = 6,
Property_Count = 7 /* One more than the number of property types. */
}
Property;
/*+ A bitmask of multiple properties. +*/
typedef uint8_t properties_t;
#define PROPERTIES(xx) (1<<((xx)-1))
/*+ The different properties as a bitmask. +*/
typedef enum _Properties
{
Properties_None = 0,
Properties_Paved = PROPERTIES(Property_Paved ),
Properties_Multilane = PROPERTIES(Property_Multilane ),
Properties_Bridge = PROPERTIES(Property_Bridge ),
Properties_Tunnel = PROPERTIES(Property_Tunnel ),
Properties_FootRoute = PROPERTIES(Property_FootRoute ),
Properties_BicycleRoute = PROPERTIES(Property_BicycleRoute ),
Properties_ALL = PROPERTIES(Property_Count )-1
}
Properties;
/*+ The speed limit of a way, measured in km/hour. +*/
typedef uint8_t speed_t;
/*+ The maximum weight of a way, measured in multiples of 0.2 tonnes. +*/
typedef uint8_t weight_t;
/*+ The maximum height of a way, measured in multiples of 0.1 metres. +*/
typedef uint8_t height_t;
/*+ The maximum width of a way, measured in multiples of 0.1 metres. +*/
typedef uint8_t width_t;
/*+ The maximum length of a way, measured in multiples of 0.1 metres. +*/
typedef uint8_t length_t;
/*+ Conversion of km/hr to speed_t - simple inline function with error checking. +*/
inline static speed_t kph_to_speed(double xxx);
inline static speed_t kph_to_speed(double xxx) { if(xxx>255) return(255); if(xxx<0) return(0); return((speed_t)xxx); }
/*+ Conversion of speed_t to km/hr. +*/
#define speed_to_kph(xxx) (int)(xxx)
/*+ Conversion of tonnes to weight_t - simple inline function with error checking. +*/
inline static weight_t tonnes_to_weight(double xxx);
inline static weight_t tonnes_to_weight(double xxx) { if(xxx>51) return(255); if(xxx<0) return(0); return((weight_t)(xxx*5)); }
/*+ Conversion of weight_t to tonnes. +*/
#define weight_to_tonnes(xxx) ((double)(xxx)/5.0)
/*+ Conversion of metres to height_t - simple inline function with error checking. +*/
inline static height_t metres_to_height(double xxx);
inline static height_t metres_to_height(double xxx) { if(xxx>25.5) return(255); if(xxx<0) return(0); return((height_t)(xxx*10)); }
/*+ Conversion of height_t to metres. +*/
#define height_to_metres(xxx) ((double)(xxx)/10.0)
/*+ Conversion of metres to width_t - simple inline function with error checking. +*/
inline static width_t metres_to_width(double xxx);
inline static width_t metres_to_width(double xxx) { if(xxx>25.5) return(255); if(xxx<0) return(0); return((width_t)(xxx*10)); }
/*+ Conversion of width_t to metres. +*/
#define width_to_metres(xxx) ((double)(xxx)/10.0)
/*+ Conversion of metres to length_t - simple inline function with error checking. +*/
inline static length_t metres_to_length(double xxx);
inline static length_t metres_to_length(double xxx) { if(xxx>25.5) return(255); if(xxx<0) return(0); return((length_t)(xxx*10)); }
/*+ Conversion of length_t to metres. +*/
#define length_to_metres(xxx) ((double)(xxx)/10.0)
/* Data structures */
typedef struct _Node Node;
typedef struct _Nodes Nodes;
typedef struct _Segment Segment;
typedef struct _Segments Segments;
typedef struct _Way Way;
typedef struct _Ways Ways;
typedef struct _TurnRelation TurnRelation;
typedef struct _Relations Relations;
/* Functions in types.c */
Highway HighwayType(const char *highway);
Transport TransportType(const char *transport);
Property PropertyType(const char *property);
const char *HighwayName(Highway highway);
const char *TransportName(Transport transport);
const char *PropertyName(Property property);
const char *HighwaysNameList(highways_t highways);
const char *TransportsNameList(transports_t transports);
const char *PropertiesNameList(properties_t properties);
const char *HighwayList(void);
const char *TransportList(void);
const char *PropertyList(void);
#endif /* TYPES_H */
routino-3.4.3/src/ways.h 644 233 144 12352 13455415301 10337 0 /***************************************
A header file for the ways.
Part of the Routino routing software.
******************/ /******************
This file Copyright 2008-2016, 2019 Andrew M. Bishop
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program 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 Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see .
***************************************/
#ifndef WAYS_H
#define WAYS_H /*+ To stop multiple inclusions. +*/
#include
#include
#include "types.h"
#include "cache.h"
#include "files.h"
/* Data structures */
/*+ A structure containing a single way (members ordered to minimise overall size). +*/
struct _Way
{
index_t name; /*+ The offset of the name of the way in the names array. +*/
transports_t allow; /*+ The type of traffic allowed on the way. +*/
highway_t type; /*+ The highway type of the way. +*/
properties_t props; /*+ The properties of the way. +*/
speed_t speed; /*+ The defined maximum speed limit of the way. +*/
weight_t weight; /*+ The defined maximum weight of traffic on the way. +*/
height_t height; /*+ The defined maximum height of traffic on the way. +*/
width_t width; /*+ The defined maximum width of traffic on the way. +*/
length_t length; /*+ The defined maximum length of traffic on the way. +*/
};
/*+ A structure containing the header from the file. +*/
typedef struct _WaysFile
{
index_t number; /*+ The number of ways. +*/
highways_t highways; /*+ The types of highways that were seen when parsing. +*/
transports_t transports; /*+ The types of traffic that were seen when parsing. +*/
properties_t properties; /*+ The properties that were seen when parsing. +*/
}
WaysFile;
/*+ A structure containing a set of ways (and pointers to mmap file). +*/
struct _Ways
{
WaysFile file; /*+ The header data from the file. +*/
#if !SLIM
char *data; /*+ The memory mapped data. +*/
Way *ways; /*+ An array of ways. +*/
char *names; /*+ An array of characters containing the names. +*/
#else
int fd; /*+ The file descriptor for the file. +*/
offset_t namesoffset; /*+ The offset of the names within the file. +*/
Way cached[3]; /*+ Two cached nodes read from the file in slim mode. +*/
char *ncached[3]; /*+ The cached way name. +*/
WayCache *cache; /*+ A RAM cache of ways read from the file. +*/
#endif
};
/* Functions in ways.c */
Ways *LoadWayList(const char *filename);
void DestroyWayList(Ways *ways);
int WaysCompare(Way *way1p,Way *way2p);
/* Macros and inline functions */
#if !SLIM
/*+ Return a Way* pointer given a set of ways and an index. +*/
#define LookupWay(xxx,yyy,zzz) (&(xxx)->ways[yyy])
/*+ Return the name of a way given the Way pointer and a set of ways. +*/
#define WayName(xxx,yyy) (&(xxx)->names[(yyy)->name])
#else
static inline Way *LookupWay(Ways *ways,index_t index,int position);
static inline char *WayName(Ways *ways,Way *wayp);
CACHE_NEWCACHE_PROTO(Way)
CACHE_DELETECACHE_PROTO(Way)
CACHE_FETCHCACHE_PROTO(Way)
CACHE_INVALIDATECACHE_PROTO(Way)
/* Data type */
CACHE_STRUCTURE(Way)
/* Inline functions */
CACHE_NEWCACHE(Way)
CACHE_DELETECACHE(Way)
CACHE_FETCHCACHE(Way)
CACHE_INVALIDATECACHE(Way)
/*++++++++++++++++++++++++++++++++++++++
Find the Way information for a particular way.
Way *LookupWay Returns a pointer to the cached way information.
Ways *ways The set of ways to use.
index_t index The index of the way.
int position The position in the cache to store the value.
++++++++++++++++++++++++++++++++++++++*/
static inline Way *LookupWay(Ways *ways,index_t index,int position)
{
ways->cached[position-1]=*FetchCachedWay(ways->cache,index,ways->fd,sizeof(WaysFile));
return(&ways->cached[position-1]);
}
/*++++++++++++++++++++++++++++++++++++++
Find the name of a way.
char *WayName Returns a pointer to the name of the way.
Ways *ways The set of ways to use.
Way *wayp The Way pointer.
++++++++++++++++++++++++++++++++++++++*/
static inline char *WayName(Ways *ways,Way *wayp)
{
int position=(int)(wayp-ways->cached);
int n=0;
if(!ways->ncached[position])
ways->ncached[position]=(char*)malloc(64);
while(!SlimFetch(ways->fd,ways->ncached[position]+n,64,ways->namesoffset+wayp->name+n))
{
int i;
for(i=n;incached[position][i]==0)
goto exitloop;
n+=64;
ways->ncached[position]=(char*)realloc((void*)ways->ncached[position],n+64);
}
exitloop:
return(ways->ncached[position]);
}
#endif
#endif /* WAYS_H */
routino-3.4.3/src/superx.c 644 233 144 37301 14242177043 10701 0 /***************************************
Super-Segment data type functions.
Part of the Routino routing software.
******************/ /******************
This file Copyright 2008-2015, 2022 Andrew M. Bishop
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program 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 Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see .
***************************************/
#include
#include "types.h"
#include "segments.h"
#include "ways.h"
#include "typesx.h"
#include "nodesx.h"
#include "segmentsx.h"
#include "waysx.h"
#include "superx.h"
#include "files.h"
#include "logging.h"
#include "results.h"
/* Local functions */
static Results *FindSuperRoutes(NodesX *nodesx,SegmentsX *segmentsx,WaysX *waysx,node_t start,Way *match);
/*++++++++++++++++++++++++++++++++++++++
Select the super-nodes from the list of nodes.
NodesX *nodesx The set of nodes to use.
SegmentsX *segmentsx The set of segments to use.
WaysX *waysx The set of ways to use.
++++++++++++++++++++++++++++++++++++++*/
void ChooseSuperNodes(NodesX *nodesx,SegmentsX *segmentsx,WaysX *waysx)
{
index_t i;
index_t nnodes=0;
if(nodesx->number==0 || segmentsx->number==0 || waysx->number==0)
return;
/* Print the start message */
printf_first("Finding Super-Nodes: Nodes=0 Super-Nodes=0");
/* Allocate and set the super-node markers */
if(!nodesx->super)
{
nodesx->super=AllocBitMask(nodesx->number);
log_malloc(nodesx->super,SizeBitMask(nodesx->number));
SetAllBits(nodesx->super,nodesx->number);
}
/* Map into memory / open the files */
nodesx->fd=ReOpenFileBuffered(nodesx->filename_tmp);
#if !SLIM
segmentsx->data=MapFile(segmentsx->filename_tmp);
waysx->data=MapFile(waysx->filename_tmp);
#else
segmentsx->fd=SlimMapFile(segmentsx->filename_tmp);
waysx->fd=SlimMapFile(waysx->filename_tmp);
InvalidateSegmentXCache(segmentsx->cache);
InvalidateWayXCache(waysx->cache);
#endif
/* Find super-nodes */
for(i=0;inumber;i++)
{
NodeX nodex;
ReadFileBuffered(nodesx->fd,&nodex,sizeof(NodeX));
if(IsBitSet(nodesx->super,i))
{
int issuper=0;
if(nodex.flags&(NODE_TURNRSTRCT|NODE_TURNRSTRCT2))
issuper=1;
else
{
int count=0,j;
Way segmentway[MAX_SEG_PER_NODE];
int segmentweight[MAX_SEG_PER_NODE];
SegmentX *segmentx=FirstSegmentX(segmentsx,i,1);
while(segmentx)
{
WayX *wayx=LookupWayX(waysx,segmentx->way,1);
int nsegments;
/* Segments that are loops count twice */
logassert(countnode1==segmentx->node2)
segmentweight[count]=2;
else
segmentweight[count]=1;
segmentway[count]=wayx->way;
/* If the node allows less traffic types than any connecting way then it is super if it allows anything */
if((wayx->way.allow&nodex.allow)!=wayx->way.allow && nodex.allow!=Transports_None)
{
issuper=1;
break;
}
nsegments=segmentweight[count];
for(j=0;jway.allow & segmentway[j].allow)
{
/* If two ways are different in any attribute and there is a type of traffic that can use both then it is super */
if(WaysCompare(&segmentway[j],&wayx->way))
{
issuper=1;
break;
}
/* If there are two other segments that can be used by the same types of traffic as this one then it is super */
nsegments+=segmentweight[j];
if(nsegments>2)
{
issuper=1;
break;
}
}
if(issuper)
break;
segmentx=NextSegmentX(segmentsx,segmentx,i);
count++;
}
}
/* Mark the node as super if it is. */
if(issuper)
nnodes++;
else
ClearBit(nodesx->super,i);
}
if(!((i+1)%10000))
printf_middle("Finding Super-Nodes: Nodes=%"Pindex_t" Super-Nodes=%"Pindex_t,i+1,nnodes);
}
/* Unmap from memory / close the files */
#if !SLIM
segmentsx->data=UnmapFile(segmentsx->data);
waysx->data=UnmapFile(waysx->data);
#else
segmentsx->fd=SlimUnmapFile(segmentsx->fd);
waysx->fd=SlimUnmapFile(waysx->fd);
#endif
nodesx->fd=CloseFileBuffered(nodesx->fd);
/* Print the final message */
printf_last("Found Super-Nodes: Nodes=%"Pindex_t" Super-Nodes=%"Pindex_t,nodesx->number,nnodes);
}
/*++++++++++++++++++++++++++++++++++++++
Create the super-segments from the existing segments.
SegmentsX *CreateSuperSegments Returns the new super segments.
NodesX *nodesx The set of nodes to use.
SegmentsX *segmentsx The set of segments to use.
WaysX *waysx The set of ways to use.
++++++++++++++++++++++++++++++++++++++*/
SegmentsX *CreateSuperSegments(NodesX *nodesx,SegmentsX *segmentsx,WaysX *waysx)
{
index_t i;
SegmentsX *supersegmentsx;
index_t sn=0,ss=0;
supersegmentsx=NewSegmentList();
if(segmentsx->number==0 || waysx->number==0)
{
FinishSegmentList(supersegmentsx);
return(supersegmentsx);
}
/* Print the start message */
printf_first("Creating Super-Segments: Super-Nodes=0 Super-Segments=0");
/* Map into memory / open the files */
#if !SLIM
nodesx->data=MapFile(nodesx->filename_tmp);
segmentsx->data=MapFile(segmentsx->filename_tmp);
waysx->data=MapFile(waysx->filename_tmp);
#else
nodesx->fd=SlimMapFile(nodesx->filename_tmp);
segmentsx->fd=SlimMapFile(segmentsx->filename_tmp);
waysx->fd=SlimMapFile(waysx->filename_tmp);
InvalidateNodeXCache(nodesx->cache);
InvalidateSegmentXCache(segmentsx->cache);
InvalidateWayXCache(waysx->cache);
#endif
/* Create super-segments for each super-node. */
for(i=0;inumber;i++)
{
if(IsBitSet(nodesx->super,i))
{
SegmentX *segmentx;
int count=0,match;
Way prevway[MAX_SEG_PER_NODE];
segmentx=FirstSegmentX(segmentsx,i,1);
while(segmentx)
{
WayX *wayx=LookupWayX(waysx,segmentx->way,1);
/* Check that this type of way hasn't already been routed */
match=0;
if(count>0)
{
int j;
for(j=0;jway))
{
match=1;
break;
}
}
logassert(countway;
/* Route the way and store the super-segments. */
if(!match)
{
Results *results=FindSuperRoutes(nodesx,segmentsx,waysx,i,&wayx->way);
Result *result=FirstResult(results);
while(result)
{
if(IsBitSet(nodesx->super,result->node) && result->segment!=NO_SEGMENT)
{
if(wayx->way.type&Highway_OneWay && result->node!=i)
AppendSegmentList(supersegmentsx,segmentx->way,i,result->node,DISTANCE((distance_t)result->score)|ONEWAY_1TO2);
else
AppendSegmentList(supersegmentsx,segmentx->way,i,result->node,DISTANCE((distance_t)result->score));
ss++;
}
result=NextResult(results,result);
}
}
segmentx=NextSegmentX(segmentsx,segmentx,i);
}
sn++;
if(!(sn%10000))
printf_middle("Creating Super-Segments: Super-Nodes=%"Pindex_t" Super-Segments=%"Pindex_t,sn,ss);
}
}
FinishSegmentList(supersegmentsx);
/* Unmap from memory / close the files */
#if !SLIM
nodesx->data=UnmapFile(nodesx->data);
segmentsx->data=UnmapFile(segmentsx->data);
waysx->data=UnmapFile(waysx->data);
#else
nodesx->fd=SlimUnmapFile(nodesx->fd);
segmentsx->fd=SlimUnmapFile(segmentsx->fd);
waysx->fd=SlimUnmapFile(waysx->fd);
#endif
/* Free the no-longer required memory */
if(segmentsx->firstnode)
{
log_free(segmentsx->firstnode);
free(segmentsx->firstnode);
segmentsx->firstnode=NULL;
}
/* Print the final message */
printf_last("Created Super-Segments: Super-Nodes=%"Pindex_t" Super-Segments=%"Pindex_t,sn,ss);
return(supersegmentsx);
}
/*++++++++++++++++++++++++++++++++++++++
Merge the segments and super-segments into a new segment list.
SegmentsX *MergeSuperSegments Returns a new set of merged segments.
SegmentsX *segmentsx The set of segments to use.
SegmentsX *supersegmentsx The set of super-segments to use.
++++++++++++++++++++++++++++++++++++++*/
SegmentsX *MergeSuperSegments(SegmentsX *segmentsx,SegmentsX *supersegmentsx)
{
index_t i,j,lastj;
index_t merged=0,added=0;
SegmentsX *mergedsegmentsx;
SegmentX supersegmentx;
mergedsegmentsx=NewSegmentList();
if(segmentsx->number==0)
{
FinishSegmentList(mergedsegmentsx);
return(mergedsegmentsx);
}
/* Print the start message */
printf_first("Merging Segments: Segments=0 Super=0 Merged=0 Added=0");
/* Open the files */
segmentsx->fd=ReOpenFileBuffered(segmentsx->filename_tmp);
if(supersegmentsx->number>0)
supersegmentsx->fd=ReOpenFileBuffered(supersegmentsx->filename_tmp);
/* Loop through and create a new list of combined segments */
lastj=-1;
j=0;
for(i=0;inumber;i++)
{
int super=0;
SegmentX segmentx;
ReadFileBuffered(segmentsx->fd,&segmentx,sizeof(SegmentX));
while(jnumber)
{
if(j!=lastj)
{
ReadFileBuffered(supersegmentsx->fd,&supersegmentx,sizeof(SegmentX));
lastj=j;
}
if(segmentx.node1 ==supersegmentx.node1 &&
segmentx.node2 ==supersegmentx.node2 &&
segmentx.distance==supersegmentx.distance)
{
merged++;
j++;
/* mark as super-segment and normal segment */
super=1;
break;
}
else if((segmentx.node1==supersegmentx.node1 &&
segmentx.node2==supersegmentx.node2) ||
(segmentx.node1==supersegmentx.node1 &&
segmentx.node2>supersegmentx.node2) ||
(segmentx.node1>supersegmentx.node1))
{
/* mark as super-segment */
AppendSegmentList(mergedsegmentsx,supersegmentx.way,supersegmentx.node1,supersegmentx.node2,supersegmentx.distance|SEGMENT_SUPER);
added++;
j++;
}
else
{
/* mark as normal segment */
break;
}
}
if(super)
AppendSegmentList(mergedsegmentsx,segmentx.way,segmentx.node1,segmentx.node2,segmentx.distance|SEGMENT_SUPER|SEGMENT_NORMAL);
else
AppendSegmentList(mergedsegmentsx,segmentx.way,segmentx.node1,segmentx.node2,segmentx.distance|SEGMENT_NORMAL);
if(!((i+1)%10000))
printf_middle("Merging Segments: Segments=%"Pindex_t" Super=%"Pindex_t" Merged=%"Pindex_t" Added=%"Pindex_t,i+1,j,merged,added);
}
if(jnumber)
{
if(j==lastj)
{
AppendSegmentList(mergedsegmentsx,supersegmentx.way,supersegmentx.node1,supersegmentx.node2,supersegmentx.distance|SEGMENT_SUPER);
j++;
}
while(jnumber)
{
ReadFileBuffered(supersegmentsx->fd,&supersegmentx,sizeof(SegmentX));
AppendSegmentList(mergedsegmentsx,supersegmentx.way,supersegmentx.node1,supersegmentx.node2,supersegmentx.distance|SEGMENT_SUPER);
added++;
j++;
}
}
FinishSegmentList(mergedsegmentsx);
/* Close the files */
segmentsx->fd=CloseFileBuffered(segmentsx->fd);
if(supersegmentsx->number>0)
supersegmentsx->fd=CloseFileBuffered(supersegmentsx->fd);
/* Print the final message */
printf_last("Merged Segments: Segments=%"Pindex_t" Super=%"Pindex_t" Merged=%"Pindex_t" Added=%"Pindex_t,segmentsx->number,supersegmentsx->number,merged,added);
return(mergedsegmentsx);
}
/*++++++++++++++++++++++++++++++++++++++
Find all routes from a specified super-node to any other super-node that follows a certain type of way.
Results *FindSuperRoutes Returns a set of results.
NodesX *nodesx The set of nodes to use.
SegmentsX *segmentsx The set of segments to use.
WaysX *waysx The set of ways to use.
node_t start The start node.
Way *match A template for the type of way that the route must follow.
++++++++++++++++++++++++++++++++++++++*/
static Results *FindSuperRoutes(NodesX *nodesx,SegmentsX *segmentsx,WaysX *waysx,node_t start,Way *match)
{
static Results *results=NULL; /* static allocation of return value (reset each call) */
static Queue *queue=NULL; /* static allocation of internal value (reset each call) */
Result *result1,*result2;
WayX *wayx;
/* Insert the first node into the queue */
if(!results)
results=NewResultsList(8);
else
ResetResultsList(results);
if(!queue)
queue=NewQueueList(8);
else
ResetQueueList(queue);
result1=InsertResult(results,start,NO_SEGMENT);
InsertInQueue(queue,result1,0);
/* Loop across all nodes in the queue */
while((result1=PopFromQueue(queue)))
{
index_t node1;
SegmentX *segmentx;
node1=result1->node;
segmentx=FirstSegmentX(segmentsx,node1,2); /* position 1 is already used */
while(segmentx)
{
NodeX *node2x;
index_t node2,seg2;
distance_t cumulative_distance;
/* must not be one-way against the direction of travel */
if(IsOnewayTo(segmentx,node1))
goto endloop;
seg2=IndexSegmentX(segmentsx,segmentx);
/* must not be a u-turn */
if(result1->segment==seg2)
goto endloop;
wayx=LookupWayX(waysx,segmentx->way,2); /* position 1 is already used */
/* must be the right type of way */
if(WaysCompare(&wayx->way,match))
goto endloop;
node2=OtherNode(segmentx,node1);
node2x=LookupNodeX(nodesx,node2,2); /* position 1 is already used */
/* Don't route beyond a node with no access */
if(node2x->allow==Transports_None)
goto endloop;
cumulative_distance=(distance_t)result1->score+DISTANCE(segmentx->distance);
result2=FindResult(results,node2,seg2);
if(!result2) /* New end node */
{
result2=InsertResult(results,node2,seg2);
result2->prev=result1;
result2->score=cumulative_distance;
/* don't route beyond a super-node. */
if(!IsBitSet(nodesx->super,node2))
InsertInQueue(queue,result2,cumulative_distance);
}
else if(cumulative_distancescore)
{
result2->prev=result1;
result2->score=cumulative_distance;
/* don't route beyond a super-node. */
if(!IsBitSet(nodesx->super,node2))
InsertInQueue(queue,result2,cumulative_distance);
}
endloop:
segmentx=NextSegmentX(segmentsx,segmentx,node1);
}
}
return(results);
}
routino-3.4.3/src/sorting.c 644 233 144 70176 14775261105 11053 0 /***************************************
Merge sort functions.
Part of the Routino routing software.
******************/ /******************
This file Copyright 2009-2015, 2017, 2019, 2023, 2025 Andrew M. Bishop
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program 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 Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see .
***************************************/
#include
#include
#include
#if defined(USE_PTHREADS) && USE_PTHREADS
#include
#endif
#include "types.h"
#include "logging.h"
#include "files.h"
#include "sorting.h"
/*+ Enable debugging print statements +*/
#define DEBUG 0
/* Global variables */
/*+ The command line '--tmpdir' option or its default value. +*/
extern char *option_tmpdirname;
/*+ The amount of RAM to use for filesorting. +*/
extern size_t option_filesort_ramsize;
/*+ The number of filesorting threads allowed. +*/
extern int option_filesort_threads;
/* Thread data type definitions */
/*+ A data type for holding data for a thread. +*/
typedef struct _thread_data
{
#if defined(USE_PTHREADS) && USE_PTHREADS
pthread_t thread; /*+ The thread identifier. +*/
int running; /*+ A flag indicating the current state of the thread. +*/
#endif
char *data; /*+ The main data array. +*/
void **datap; /*+ An array of pointers to the data objects. +*/
size_t n; /*+ The number of pointers. +*/
int fd; /*+ The file descriptor of the file to write the results to. +*/
size_t itemsize; /*+ The size of each item. +*/
int (*compare)(const void*,const void*); /*+ The comparison function. +*/
}
thread_data;
/* Thread variables and functions */
#if defined(USE_PTHREADS) && USE_PTHREADS
static pthread_mutex_t running_mutex = PTHREAD_MUTEX_INITIALIZER;
static pthread_cond_t running_cond = PTHREAD_COND_INITIALIZER;
static int wait_for_free_thread(thread_data *threads,int nthreads,int *threads_running);
static void wait_for_all_threads(thread_data *threads,int nthreads,int *threads_running);
#endif
/* Thread helper functions */
static void *filesort_heapsort_thread(thread_data *thread);
/* Local functions */
static index_t filesort_merge(int fd_out,int nfiles,size_t itemsize,size_t largestitemsize,
int(*compare_function)(const void*, const void*),
int (*post_sort_function)(void*,index_t));
/*++++++++++++++++++++++++++++++++++++++
A function to sort the contents of a file of fixed length objects using a
limited amount of RAM.
The data is sorted using a "Merge sort" http://en.wikipedia.org/wiki/Merge_sort
and in particular an "external sort" http://en.wikipedia.org/wiki/External_sorting.
The individual sort steps and the merge step both use a "Heap sort"
http://en.wikipedia.org/wiki/Heapsort. The combination of the two should work well
if the data is already partially sorted.
index_t filesort_fixed Returns the number of objects kept.
int fd_in The file descriptor of the input file (opened for reading and at the beginning).
int fd_out The file descriptor of the output file (opened for writing and empty).
size_t itemsize The size of each item in the file that needs sorting.
int (*pre_sort_function)(void *,index_t) If non-NULL then this function is called for
each item before they have been sorted. The second parameter is the number of objects
previously read from the input file. If the function returns 1 then the object is kept
and it is sorted, otherwise it is ignored.
int (*compare_function)(const void*, const void*) The comparison function. This is identical
to qsort if the data to be sorted is an array of things not pointers.
int (*post_sort_function)(void *,index_t) If non-NULL then this function is called for
each item after they have been sorted. The second parameter is the number of objects
already written to the output file. If the function returns 1 then the object is written
to the output file., otherwise it is ignored.
++++++++++++++++++++++++++++++++++++++*/
index_t filesort_fixed(int fd_in,int fd_out,size_t itemsize,int (*pre_sort_function)(void*,index_t),
int (*compare_function)(const void*,const void*),
int (*post_sort_function)(void*,index_t))
{
int nfiles=0;
index_t count_out=0,count_in=0,total=0;
size_t nitems,item;
thread_data *threads;
int nthreads,i,more=1;
char *filename=(char*)malloc_logassert(strlen(option_tmpdirname)+24);
#if defined(USE_PTHREADS) && USE_PTHREADS
int threads_running=0;
#endif
/* Allocate the RAM buffer and other bits */
nitems=(size_t)SizeFileFD(fd_in)/itemsize;
if(nitems==0)
return(0);
if(option_filesort_threads==1)
nthreads = 1;
else if((nitems*(itemsize+sizeof(void*)))option_filesort_ramsize)
nitems=option_filesort_ramsize/(itemsize+sizeof(void*));
nitems=1+nitems/nthreads;
#if DEBUG
printf("DEBUG: filesort_fixed nitems=%lu option_ramsize/option_threads=%lu => nitems=%lu datasize=%lu nthreads=%d\n",
(size_t)SizeFileFD(fd_in)/itemsize,option_filesort_ramsize/option_filesort_threads,nitems,nitems*(itemsize+sizeof(void*)),nthreads);
#endif
threads=(thread_data*)calloc_logassert(nthreads,sizeof(thread_data));
for(i=0;i1)
thread=wait_for_free_thread(threads,nthreads,&threads_running);
#endif
/* Read in the data and create pointers */
for(item=0;item1)
wait_for_all_threads(threads,nthreads,&threads_running);
#endif
/* Shortcut if there are no files */
if(nfiles==0)
goto tidy_and_exit;
/* Shortcut if only one file, lucky for us we still have the data in RAM) */
if(nfiles==1)
{
for(item=0;itemoption_filesort_ramsize)
datasize=option_filesort_ramsize;
datasize=datasize/nthreads;
datasize=FILESORT_VARALIGN*((datasize+FILESORT_VARALIGN-1)/FILESORT_VARALIGN);
#if DEBUG
printf("DEBUG: filesort_vary datasize=%lu option_ramsize/option_threads=%lu => datasize=%lu nthreads=%d\n",
2*(size_t)SizeFileFD(fd_in),option_filesort_ramsize/option_filesort_threads,datasize,nthreads);
#endif
threads=(thread_data*)calloc_logassert(nthreads,sizeof(thread_data));
for(i=0;i1)
thread=wait_for_free_thread(threads,nthreads,&threads_running);
#endif
threads[thread].datap=(void**)(threads[thread].data+datasize);
item=0;
/* Read in the data and create pointers */
while((ramused+FILESORT_VARSIZE+nextitemsize)<=(size_t)((char*)threads[thread].datap-sizeof(void*)-threads[thread].data))
{
FILESORT_VARINT itemsize=nextitemsize;
*(FILESORT_VARINT*)(threads[thread].data+ramused)=itemsize;
ramused+=FILESORT_VARSIZE;
ReadFileBuffered(fd_in,threads[thread].data+ramused,itemsize);
if(!pre_sort_function || pre_sort_function(threads[thread].data+ramused,count_in))
{
*--threads[thread].datap=threads[thread].data+ramused; /* points to real data */
if(itemsize>largestitemsize)
largestitemsize=itemsize;
ramused+=itemsize;
ramused =FILESORT_VARALIGN*((ramused+FILESORT_VARALIGN-1)/FILESORT_VARALIGN);
ramused+=FILESORT_VARALIGN-FILESORT_VARSIZE;
total++;
item++;
}
else
ramused-=FILESORT_VARSIZE;
count_in++;
if(ReadFileBuffered(fd_in,&nextitemsize,FILESORT_VARSIZE))
{
more=0;
break;
}
}
#if DEBUG
printf("DEBUG: filesort_vary thread=%d file=%d item=%lu total=%u ramused=%lu more=%d\n",thread,nfiles,item,total,ramused+item*sizeof(void*),more);
#endif
/* No new data read in this time round */
if(item==0)
break;
/* Update the number of items to sort */
threads[thread].n=item;
/* Shortcut if only one file, don't write to disk */
if(more==0 && nfiles==0)
{
filename[0]=0;
filesort_heapsort_thread(&threads[thread]);
}
else
{
/* Create the file descriptor (not thread-safe) */
sprintf(filename,"%s/filesort.%d.tmp",option_tmpdirname,nfiles);
threads[thread].fd=OpenFileBufferedNew(filename);
if(nthreads==1)
{
filesort_heapsort_thread(&threads[thread]);
CloseFileBuffered(threads[thread].fd);
}
#if defined(USE_PTHREADS) && USE_PTHREADS
else
{
threads[thread].running=1;
pthread_create(&threads[thread].thread,NULL,(void* (*)(void*))filesort_heapsort_thread,&threads[thread]);
threads_running++;
}
#endif
}
nfiles++;
}
while(more);
#if defined(USE_PTHREADS) && USE_PTHREADS
/* Wait for all of the threads to finish */
if(nthreads>1)
wait_for_all_threads(threads,nthreads,&threads_running);
#endif
/* Shortcut if there are no files */
if(nfiles==0)
goto tidy_and_exit;
/* Shortcut if only one file, lucky for us we still have the data in RAM) */
if(nfiles==1)
{
for(item=0;itemdatap,thread->n,thread->compare);
/* Write the result to the temporary file if given */
if(thread->fd>0)
{
if(thread->itemsize>0)
for(item=0;itemn;item++)
WriteFileBuffered(thread->fd,thread->datap[item],thread->itemsize);
else
for(item=0;itemn;item++)
{
FILESORT_VARINT itemsize=*(FILESORT_VARINT*)((char*)thread->datap[item]-FILESORT_VARSIZE);
WriteFileBuffered(thread->fd,(char*)thread->datap[item]-FILESORT_VARSIZE,itemsize+FILESORT_VARSIZE);
}
}
#if defined(USE_PTHREADS) && USE_PTHREADS
/* Signal that this thread has finished */
if(thread->running==1)
{
pthread_mutex_lock(&running_mutex);
thread->running=2;
pthread_cond_signal(&running_cond);
pthread_mutex_unlock(&running_mutex);
}
#endif
return(NULL);
}
/*++++++++++++++++++++++++++++++++++++++
A function to sort an array of pointers efficiently.
The data is sorted using a "Heap sort" http://en.wikipedia.org/wiki/Heapsort,
in particular, this is good because it can operate in-place and doesn't
allocate more memory like using qsort() does.
void **datap A pointer to the array of pointers to sort.
size_t nitems The number of items of data to sort.
int (*compare_function)(const void*, const void*) The comparison function. This is identical
to qsort if the data to be sorted is an array of things not pointers.
++++++++++++++++++++++++++++++++++++++*/
void filesort_heapsort(void **datap,size_t nitems,int(*compare_function)(const void*, const void*))
{
void **datap1=&datap[-1];
size_t item;
/* Fill the heap by pretending to insert the data that is already there */
for(item=2;item<=nitems;item++)
{
size_t index=item;
/* Bubble up the new value (upside-down, put largest at top) */
while(index>1)
{
int newindex;
void *temp;
newindex=index/2;
if(compare_function(datap1[index],datap1[newindex])<=0) /* reversed comparison to filesort_fixed() above */
break;
temp=datap1[index];
datap1[index]=datap1[newindex];
datap1[newindex]=temp;
index=newindex;
}
}
/* Repeatedly pull out the root of the heap and swap with the bottom item */
for(item=nitems;item>1;item--)
{
size_t index=1;
void *temp;
temp=datap1[index];
datap1[index]=datap1[item];
datap1[item]=temp;
/* Bubble down the new value (upside-down, put largest at top) */
while((2*index)<(item-1))
{
int newindex;
void **temp;
newindex=2*index;
if(compare_function(datap1[newindex],datap1[newindex+1])<=0) /* reversed comparison to filesort_fixed() above */
newindex=newindex+1;
if(compare_function(datap1[index],datap1[newindex])>=0) /* reversed comparison to filesort_fixed() above */
break;
temp=datap1[newindex];
datap1[newindex]=datap1[index];
datap1[index]=temp;
index=newindex;
}
if((2*index)==(item-1))
{
int newindex;
void *temp;
newindex=2*index;
if(compare_function(datap1[index],datap1[newindex])>=0) /* reversed comparison to filesort_fixed() above */
; /* break */
else
{
temp=datap1[newindex];
datap1[newindex]=datap1[index];
datap1[index]=temp;
}
}
}
}
/*++++++++++++++++++++++++++++++++++++++
A function to merge an array of sorted files efficiently.
The data is merged using an "external sort" http://en.wikipedia.org/wiki/External_sorting
where only one item is read from each file at a time.
index_t filesort_merge Returns the number of items written to the output file
int fd_out The file descriptor of the output file (opened for writing and empty).
int nfiles The number of files to open and merge
size_t itemsize The size of each item (non-zero if a fixed size sort).
size_t largestitemsize The maximum size of each item (non-zero if a variable size sort).
int (*compare_function)(const void*, const void*) The comparison function. This is identical
to qsort if the data to be sorted is an array of things not pointers.
int (*post_sort_function)(void *,index_t) If non-NULL then this function is called for
each item after they have been sorted. The second parameter is the number of objects
already written to the output file. If the function returns 1 then the object is written
to the output file., otherwise it is ignored.
++++++++++++++++++++++++++++++++++++++*/
static index_t filesort_merge(int fd_out,int nfiles,size_t itemsize,size_t largestitemsize,
int(*compare_function)(const void*, const void*),
int (*post_sort_function)(void*,index_t))
{
int ndata=0;
char *data,*filename;
void **datap;
int *fds,*heap;
index_t count_out=0;
int i;
/* Allocate the memory */
filename=(char*)malloc_logassert(strlen(option_tmpdirname)+24);
heap=(int*)malloc_logassert((1+nfiles)*sizeof(int));
if(itemsize)
data=(void*)malloc_logassert(nfiles*itemsize);
else
data=(void*)malloc_logassert(nfiles*(largestitemsize+FILESORT_VARALIGN));
datap=(void**)malloc_logassert(nfiles*sizeof(void*));
fds=(int*)malloc_logassert(nfiles*sizeof(int));
/* Re-open the files */
for(i=0;i1)
{
int newindex;
int temp;
newindex=index/2;
if(compare_function(datap[heap[index]],datap[heap[newindex]])>=0)
break;
temp=heap[index];
heap[index]=heap[newindex];
heap[newindex]=temp;
index=newindex;
}
}
/* Repeatedly pull out the root of the heap and refill from the same file */
ndata=nfiles;
do
{
int index=1;
if(!post_sort_function || post_sort_function(datap[heap[index]],count_out))
{
if(itemsize)
WriteFileBuffered(fd_out,datap[heap[index]],itemsize);
else
{
FILESORT_VARINT itemsize=*(FILESORT_VARINT*)((char*)datap[heap[index]]-FILESORT_VARSIZE);
WriteFileBuffered(fd_out,(char*)datap[heap[index]]-FILESORT_VARSIZE,itemsize+FILESORT_VARSIZE);
}
count_out++;
}
if(itemsize)
{
if(ReadFileBuffered(fds[heap[index]],datap[heap[index]],itemsize))
{
heap[index]=heap[ndata];
ndata--;
}
}
else
{
FILESORT_VARINT itemsize;
if(ReadFileBuffered(fds[heap[index]],&itemsize,FILESORT_VARSIZE))
{
heap[index]=heap[ndata];
ndata--;
}
else
{
*(FILESORT_VARINT*)((char*)datap[heap[index]]-FILESORT_VARSIZE)=itemsize;
ReadFileBuffered(fds[heap[index]],datap[heap[index]],itemsize);
}
}
/* Bubble down the new value */
while((2*index)=0)
newindex=newindex+1;
if(compare_function(datap[heap[index]],datap[heap[newindex]])<=0)
break;
temp=heap[newindex];
heap[newindex]=heap[index];
heap[index]=temp;
index=newindex;
}
if((2*index)==ndata)
{
int newindex;
int temp;
newindex=2*index;
if(compare_function(datap[heap[index]],datap[heap[newindex]])<=0)
; /* break */
else
{
temp=heap[newindex];
heap[newindex]=heap[index];
heap[index]=temp;
}
}
}
while(ndata>0);
/* Tidy up */
free(filename);
for(i=0;i