Skip to content
GitLab
Menu
Projects
Groups
Snippets
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
Menu
Open sidebar
PIM
KItinerary
Commits
d3c4a902
Commit
d3c4a902
authored
Apr 21, 2020
by
Volker Krause
Browse files
Clean up manual airport polygon assembly code
We now have this available generically in the library.
parent
4901a61e
Changes
2
Hide whitespace changes
Inline
Side-by-side
src/knowledgedb-generator/osmairportdb.cpp
View file @
d3c4a902
...
...
@@ -28,21 +28,6 @@ enum {
StationToTerminalDistance
=
75
,
// in meter
};
template
<
typename
T
>
static
bool
isActiveAirport
(
const
T
&
elem
)
{
// filter out airports we aren't interested in
// not strictly needed here, but it reduces the diagnostic noise
const
auto
disused
=
OSM
::
tagValue
(
elem
,
QLatin1String
(
"disused"
));
const
auto
militayLanduse
=
OSM
::
tagValue
(
elem
,
QLatin1String
(
"landuse"
))
==
QLatin1String
(
"military"
);
if
(
!
disused
.
isEmpty
()
||
militayLanduse
)
{
return
false
;
}
const
auto
aeroway
=
OSM
::
tagValue
(
elem
,
QLatin1String
(
"aeroway"
));
return
aeroway
==
QLatin1String
(
"aerodrome"
);
}
void
OSMAirportDb
::
load
(
const
QString
&
path
)
{
QFile
f
(
path
);
...
...
@@ -62,24 +47,13 @@ void OSMAirportDb::load(const QString &path)
// as a single node: we don't care, this doesn't improve coordinate information for our use-case
// as a single way for the outer shape
// as a relation representing a multi-polygon outer shape
for
(
const
auto
&
rel
:
m_dataset
.
relations
)
{
loadAirport
(
rel
);
}
for
(
const
auto
&
way
:
m_dataset
.
ways
)
{
if
(
isActiveAirport
(
way
))
{
loadAirport
(
way
);
}
}
// resolve multi-path polygons
for
(
auto
&
it
:
m_iataMap
)
{
resolveAirportPaths
(
it
.
second
);
}
OSM
::
for_each
(
m_dataset
,
[
this
](
auto
elem
)
{
loadAirport
(
elem
);
},
OSM
::
IncludeRelations
|
OSM
::
IncludeWays
);
// find all terminal buildings, and add them to their airports
OSM
::
for_each
(
m_dataset
,
[
this
](
const
auto
&
elem
)
{
loadTerminal
(
elem
);
});
OSM
::
for_each
(
m_dataset
,
[
this
](
auto
elem
)
{
loadTerminal
(
elem
);
});
// load railway stations
OSM
::
for_each
(
m_dataset
,
[
this
](
const
auto
&
elem
)
{
loadStation
(
elem
);
});
OSM
::
for_each
(
m_dataset
,
[
this
](
auto
elem
)
{
loadStation
(
elem
);
});
for
(
auto
&
a
:
m_iataMap
)
{
filterStations
(
a
.
second
);
}
...
...
@@ -100,9 +74,22 @@ void OSMAirportDb::load(const QString &path)
});
}
template
<
typename
T
>
void
OSMAirportDb
::
loadAirport
(
const
T
&
elem
)
void
OSMAirportDb
::
loadAirport
(
OSM
::
Element
elem
)
{
const
auto
iata
=
OSM
::
tagValue
(
elem
,
QLatin1String
(
"iata"
));
const
auto
aeroway
=
elem
.
tagValue
(
QLatin1String
(
"aeroway"
));
if
(
aeroway
!=
QLatin1String
(
"aerodrome"
))
{
return
;
}
// filter out airports we aren't interested in
// not strictly needed here, but it reduces the diagnostic noise
const
auto
disused
=
elem
.
tagValue
(
QLatin1String
(
"disused"
));
const
auto
militayLanduse
=
elem
.
tagValue
(
QLatin1String
(
"landuse"
))
==
QLatin1String
(
"military"
);
if
(
!
disused
.
isEmpty
()
||
militayLanduse
)
{
return
;
}
const
auto
iata
=
elem
.
tagValue
(
QLatin1String
(
"iata"
));
if
(
iata
.
isEmpty
())
{
return
;
}
...
...
@@ -111,93 +98,65 @@ template<typename T> void OSMAirportDb::loadAirport(const T &elem)
if
(
iata
.
contains
(
QLatin1Char
(
';'
)))
{
const
auto
iatas
=
iata
.
split
(
QLatin1Char
(
';'
),
Qt
::
SkipEmptyParts
);
for
(
const
auto
&
iata
:
iatas
)
{
auto
e
=
elem
;
OSM
::
setTagValue
(
e
,
QStringLiteral
(
"iata"
),
iata
);
loadAirport
(
e
);
loadAirport
(
elem
,
iata
);
}
return
;
}
if
(
iata
.
size
()
!=
3
||
!
std
::
all_of
(
iata
.
begin
(),
iata
.
end
(),
[](
const
auto
c
)
{
return
c
.
isUpper
();
}))
{
qWarning
()
<<
"IATA code format violation:"
<<
iata
<<
elem
.
url
();
return
;
}
else
{
loadAirport
(
elem
,
iata
);
}
loadAirport
(
elem
,
iata
);
}
void
OSMAirportDb
::
loadAirport
(
const
OSM
::
Relation
&
elem
,
const
QString
&
i
at
aCode
)
static
QPolygonF
polygonFromOuterPath
(
const
std
::
vector
<
const
OSM
::
Node
*>
&
p
at
h
)
{
if
(
!
isActiveAirport
(
elem
))
{
return
;
}
const
auto
it
=
m_iataMap
.
find
(
iataCode
);
if
(
it
!=
m_iataMap
.
end
())
{
qWarning
()
<<
"Duplicate relation for IATA code:"
<<
iataCode
<<
(
*
it
).
second
.
source
<<
elem
.
url
();
return
;
if
(
path
.
empty
())
{
return
{};
}
OSMAirportData
airport
;
airport
.
source
=
elem
.
url
();
airport
.
bbox
=
elem
.
bbox
;
m_iataMap
[
iataCode
]
=
std
::
move
(
airport
);
// we assume type == multipolygon here
for
(
const
auto
&
member
:
elem
.
members
)
{
if
(
member
.
role
!=
QLatin1String
(
"outer"
))
{
continue
;
}
const
auto
it
=
std
::
lower_bound
(
m_dataset
.
ways
.
begin
(),
m_dataset
.
ways
.
end
(),
member
.
id
);
if
(
it
!=
m_dataset
.
ways
.
end
()
&&
(
*
it
).
id
==
member
.
id
)
{
loadAirport
(
*
it
,
iataCode
);
QPolygonF
subPoly
,
result
;
subPoly
.
push_back
(
QPointF
(
path
[
0
]
->
coordinate
.
latF
(),
path
[
0
]
->
coordinate
.
lonF
()));
OSM
::
Id
firstNode
=
path
[
0
]
->
id
;
for
(
auto
it
=
std
::
next
(
path
.
begin
());
it
!=
path
.
end
();
++
it
)
{
if
(
firstNode
==
0
)
{
// starting a new loop
firstNode
=
(
*
it
)
->
id
;
subPoly
.
push_back
(
QPointF
((
*
it
)
->
coordinate
.
latF
(),
(
*
it
)
->
coordinate
.
lonF
()));
}
else
if
((
*
it
)
->
id
==
firstNode
)
{
// just closed a loop, so this is not a line on the path
subPoly
.
push_back
(
QPointF
((
*
it
)
->
coordinate
.
latF
(),
(
*
it
)
->
coordinate
.
lonF
()));
firstNode
=
0
;
result
=
result
.
united
(
subPoly
);
subPoly
.
clear
();
}
else
{
subPoly
.
push_back
(
QPointF
((
*
it
)
->
coordinate
.
latF
(),
(
*
it
)
->
coordinate
.
lonF
()));
}
}
if
(
!
subPoly
.
empty
())
{
result
=
result
.
united
(
subPoly
);
}
return
result
;
}
void
OSMAirportDb
::
loadAirport
(
const
OSM
::
Way
&
elem
,
const
QString
&
iataCode
)
void
OSMAirportDb
::
loadAirport
(
OSM
::
Element
elem
,
const
QString
&
iataCode
)
{
if
(
elem
.
n
ode
s
.
e
mpty
(
))
{
qWarning
()
<<
"
Empty way element!"
<<
elem
.
url
();
if
(
iataCode
.
size
()
!=
3
||
!
std
::
all_of
(
iataCode
.
begin
(),
iataC
ode
.
e
nd
(),
[](
const
auto
c
)
{
return
c
.
isUpper
();
}
))
{
qWarning
()
<<
"
IATA code format violation:"
<<
iataCode
<<
elem
.
url
();
return
;
}
const
auto
it
=
m_iataMap
.
find
(
iataCode
);
if
(
it
!=
m_iataMap
.
end
())
{
// check if this overlaps, then it's just multiple parts of the same airport, otherwise this is a suspected IATA code duplication
if
((
*
it
).
second
.
bbox
.
isValid
()
&&
!
OSM
::
intersects
((
*
it
).
second
.
bbox
,
elem
.
bbox
))
{
// TODO we probably want to exclude the entire code as invalid then
qWarning
()
<<
"duplicate IATA code?"
<<
(
*
it
).
first
<<
elem
.
url
()
<<
(
*
it
).
second
.
source
;
}
else
{
//qDebug() << "merging airport parts:" << iataCode << (*it).second.source << elem.url();
(
*
it
).
second
.
bbox
=
OSM
::
unite
((
*
it
).
second
.
bbox
,
elem
.
bbox
);
if
(
elem
.
isClosed
())
{
QVector
<
QPointF
>
points
;
points
.
reserve
(
elem
.
nodes
.
size
());
appendPointsFromWay
(
points
,
elem
.
nodes
.
begin
(),
elem
.
nodes
.
end
());
(
*
it
).
second
.
airportPolygon
=
(
*
it
).
second
.
airportPolygon
.
united
(
QPolygonF
(
points
));
}
else
{
(
*
it
).
second
.
airportPaths
.
push_back
(
&
elem
);
}
}
if
(
it
!=
m_iataMap
.
end
()
&&
!
OSM
::
intersects
((
*
it
).
second
.
bbox
,
elem
.
boundingBox
()))
{
qWarning
()
<<
"Duplicate IATA code:"
<<
iataCode
<<
(
*
it
).
second
.
source
<<
elem
.
url
();
return
;
}
//qDebug() << iata << elem.bbox << elem.id;
OSMAirportData
airport
;
airport
.
source
=
elem
.
url
();
airport
.
bbox
=
elem
.
bbox
;
if
(
elem
.
isClosed
())
{
QVector
<
QPointF
>
points
;
points
.
reserve
(
elem
.
nodes
.
size
());
appendPointsFromWay
(
points
,
elem
.
nodes
.
begin
(),
elem
.
nodes
.
end
());
airport
.
airportPolygon
=
QPolygonF
(
points
);
const
auto
poly
=
polygonFromOuterPath
(
elem
.
outerPath
(
m_dataset
));
if
(
it
!=
m_iataMap
.
end
())
{
(
*
it
).
second
.
bbox
=
OSM
::
unite
(
elem
.
boundingBox
(),
(
*
it
).
second
.
bbox
);
(
*
it
).
second
.
airportPolygon
=
(
*
it
).
second
.
airportPolygon
.
united
(
poly
);
}
else
{
airport
.
airportPaths
.
push_back
(
&
elem
);
OSMAirportData
airport
;
airport
.
source
=
elem
.
url
();
airport
.
bbox
=
elem
.
boundingBox
();
airport
.
airportPolygon
=
poly
;
m_iataMap
[
iataCode
]
=
std
::
move
(
airport
);
}
m_iataMap
[
iataCode
]
=
std
::
move
(
airport
);
}
void
OSMAirportDb
::
loadTerminal
(
OSM
::
Element
elem
)
...
...
@@ -382,75 +341,3 @@ OSM::Coordinate OSMAirportDb::lookup(const QString &iata, float lat, float lon)
return
{};
}
template
<
typename
Iter
>
void
OSMAirportDb
::
appendPointsFromWay
(
QVector
<
QPointF
>&
points
,
const
Iter
&
nodeBegin
,
const
Iter
&
nodeEnd
)
const
{
points
.
reserve
(
points
.
size
()
+
std
::
distance
(
nodeBegin
,
nodeEnd
));
for
(
auto
it
=
nodeBegin
;
it
!=
nodeEnd
;
++
it
)
{
const
auto
nodeIt
=
std
::
lower_bound
(
m_dataset
.
nodes
.
begin
(),
m_dataset
.
nodes
.
end
(),
(
*
it
));
if
(
nodeIt
==
m_dataset
.
nodes
.
end
()
||
(
*
nodeIt
).
id
!=
(
*
it
))
{
continue
;
}
points
.
push_back
(
QPointF
((
*
nodeIt
).
coordinate
.
latF
(),
(
*
nodeIt
).
coordinate
.
lonF
()));
}
}
OSM
::
Id
OSMAirportDb
::
appendNextPath
(
QVector
<
QPointF
>
&
points
,
OSM
::
Id
startNode
,
OSMAirportData
&
airport
)
const
{
if
(
airport
.
airportPaths
.
empty
())
{
return
{};
}
for
(
auto
it
=
airport
.
airportPaths
.
begin
()
+
1
;
it
!=
airport
.
airportPaths
.
end
();
++
it
)
{
assert
(
!
(
*
it
)
->
nodes
.
empty
());
// ensured above
//qDebug() << " looking at:" << (*it)->nodes.front() << (*it)->url();
if
((
*
it
)
->
nodes
.
front
()
==
startNode
)
{
appendPointsFromWay
(
points
,
(
*
it
)
->
nodes
.
begin
(),
(
*
it
)
->
nodes
.
end
());
const
auto
lastNodeId
=
(
*
it
)
->
nodes
.
back
();
airport
.
airportPaths
.
erase
(
it
);
return
lastNodeId
;
}
// path segments can also be backwards
if
((
*
it
)
->
nodes
.
back
()
==
startNode
)
{
appendPointsFromWay
(
points
,
(
*
it
)
->
nodes
.
rbegin
(),
(
*
it
)
->
nodes
.
rend
());
const
auto
lastNodeId
=
(
*
it
)
->
nodes
.
front
();
airport
.
airportPaths
.
erase
(
it
);
return
lastNodeId
;
}
}
return
{};
}
void
OSMAirportDb
::
resolveAirportPaths
(
OSMAirportData
&
airport
)
const
{
//qDebug() << "resolving polygon for" << airport.source << airport.bbox << airport.airportPaths.size();
for
(
auto
it
=
airport
.
airportPaths
.
begin
();
it
!=
airport
.
airportPaths
.
end
();)
{
assert
(
!
(
*
it
)
->
nodes
.
empty
());
// ensured above
if
(
airport
.
airportPaths
.
size
()
==
1
)
{
qWarning
()
<<
" open airport polgyon:"
<<
airport
.
source
<<
(
*
it
)
->
url
();
return
;
}
QVector
<
QPointF
>
points
;
appendPointsFromWay
(
points
,
(
*
it
)
->
nodes
.
begin
(),
(
*
it
)
->
nodes
.
end
());
const
auto
startNode
=
(
*
it
)
->
nodes
.
front
();
auto
lastNode
=
(
*
it
)
->
nodes
.
back
();
//qDebug() << " starting:" << startNode << lastNode << (*it)->url();
do
{
lastNode
=
appendNextPath
(
points
,
lastNode
,
airport
);
//qDebug() << " next:" << lastNode;
}
while
(
lastNode
&&
lastNode
!=
startNode
);
if
(
lastNode
!=
startNode
)
{
qWarning
()
<<
" open airport polygon:"
<<
airport
.
source
<<
(
*
it
)
->
url
();
}
else
{
airport
.
airportPolygon
=
airport
.
airportPolygon
.
united
(
QPolygonF
(
points
));
}
it
=
airport
.
airportPaths
.
erase
(
it
);
}
//qDebug() << " polygon:" << airport.airportPolygon.size() << airport.airportPolygon.boundingRect();
}
src/knowledgedb-generator/osmairportdb.h
View file @
d3c4a902
...
...
@@ -31,7 +31,6 @@ struct OSMAirportData
QString
source
;
// OSM URL, for diagnostics only
OSM
::
BoundingBox
bbox
;
std
::
vector
<
const
OSM
::
Way
*>
airportPaths
;
QPolygonF
airportPolygon
;
std
::
vector
<
OSM
::
Element
>
terminals
;
...
...
@@ -47,18 +46,12 @@ public:
OSM
::
Coordinate
lookup
(
const
QString
&
iata
,
float
lat
,
float
lon
);
private:
template
<
typename
T
>
void
loadAirport
(
const
T
&
elem
);
void
loadAirport
(
const
OSM
::
Relation
&
elem
,
const
QString
&
iataCode
);
void
loadAirport
(
const
OSM
::
Way
&
elem
,
const
QString
&
iataCode
);
void
loadAirport
(
OSM
::
Element
elem
);
void
loadAirport
(
OSM
::
Element
elem
,
const
QString
&
iataCode
);
void
loadTerminal
(
OSM
::
Element
elem
);
void
loadStation
(
OSM
::
Element
elem
);
void
filterStations
(
OSMAirportData
&
airport
);
template
<
typename
Iter
>
void
appendPointsFromWay
(
QVector
<
QPointF
>
&
points
,
const
Iter
&
nodeEegin
,
const
Iter
&
nodeEnd
)
const
;
OSM
::
Id
appendNextPath
(
QVector
<
QPointF
>
&
points
,
OSM
::
Id
startNode
,
OSMAirportData
&
airport
)
const
;
void
resolveAirportPaths
(
OSMAirportData
&
airport
)
const
;
OSM
::
DataSet
m_dataset
;
std
::
map
<
QString
,
OSMAirportData
>
m_iataMap
;
};
...
...
Write
Preview
Supports
Markdown
0%
Try again
or
attach a new file
.
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment