Added nodiscard

This commit is contained in:
Robert 2021-04-18 15:44:48 +02:00
parent d8c11c48c9
commit 87046f5d18
6 changed files with 99 additions and 260 deletions

View file

@ -22,12 +22,12 @@ namespace osmp
IMember(const IMember& other) = delete;
virtual ~IMember() {}
IMember::Type GetType() const;
[[nodiscard]] IMember::Type GetType() const;
const std::vector<Tag>& GetTags() const;
size_t GetTagsSize() const;
const Tag& GetTag(size_t index) const;
std::string GetTag(const std::string& key) const;
[[nodiscard]] const std::vector<Tag>& GetTags() const;
[[nodiscard]] size_t GetTagsSize() const;
[[nodiscard]] const Tag& GetTag(size_t index) const;
[[nodiscard]] std::string GetTag(const std::string& key) const;
protected:
IMember(const tinyxml2::XMLElement* element, Object* parent, IMember::Type type);

View file

@ -15,20 +15,20 @@ namespace osmp
class Object
{
public:
Object(const std::string& file);
explicit Object(const std::string& file);
~Object();
std::vector<std::shared_ptr<Node>> GetNodes() const;
size_t GetNodesSize() const;
std::shared_ptr<Node> GetNode(uint64_t id) const;
[[nodiscard]] std::vector<std::shared_ptr<Node>> GetNodes() const;
[[nodiscard]] size_t GetNodesSize() const;
[[nodiscard]] std::shared_ptr<Node> GetNode(uint64_t id) const;
std::vector<std::shared_ptr<Way>> GetWays() const;
size_t GetWaysSize() const;
std::shared_ptr<Way> GetWay(uint64_t id) const;
[[nodiscard]] std::vector<std::shared_ptr<Way>> GetWays() const;
[[nodiscard]] size_t GetWaysSize() const;
[[nodiscard]] std::shared_ptr<Way> GetWay(uint64_t id) const;
std::vector<std::shared_ptr<Relation>> GetRelations() const;
size_t GetRelationsSize() const;
std::shared_ptr<Relation> GetRelation(uint64_t id) const;
[[nodiscard]] std::vector<std::shared_ptr<Relation>> GetRelations() const;
[[nodiscard]] size_t GetRelationsSize() const;
[[nodiscard]] std::shared_ptr<Relation> GetRelation(uint64_t id) const;
public:
const std::string version;

View file

@ -21,17 +21,17 @@ namespace osmp
public:
Relation(const tinyxml2::XMLElement* xml, Object* parent);
std::string GetRelationType();
[[nodiscard]] std::string GetRelationType();
const std::vector<Member>& GetNodes() const;
size_t GetNodesSize() const;
const Member& GetNode(size_t index) const;
[[nodiscard]] const std::vector<Member>& GetNodes() const;
[[nodiscard]] size_t GetNodesSize() const;
[[nodiscard]] const Member& GetNode(size_t index) const;
const std::vector<Member>& GetWays() const;
size_t GetWaysSize() const;
const Member& GetWay(size_t index) const;
[[nodiscard]] const std::vector<Member>& GetWays() const;
[[nodiscard]] size_t GetWaysSize() const;
[[nodiscard]] const Member& GetWay(size_t index) const;
bool HasNullMembers() const { return hasNullMembers; }
[[nodiscard]] bool HasNullMembers() const { return hasNullMembers; }
private:
std::string relationType;

View file

@ -16,9 +16,9 @@ namespace osmp
public:
Way(const tinyxml2::XMLElement* way_elem, Object* parent);
const std::vector<std::shared_ptr<Node>>& GetNodes() const;
size_t GetNodesSize() const;
const std::shared_ptr<Node>& GetNode(size_t index) const;
[[nodiscard]] const std::vector<std::shared_ptr<Node>>& GetNodes() const;
[[nodiscard]] size_t GetNodesSize() const;
[[nodiscard]] const std::shared_ptr<Node>& GetNode(size_t index) const;
public:
bool area, closed; // Closed := Startpoint = endpoint, Area := Closed AND certain conditions are not met

View file

@ -14,8 +14,8 @@ namespace osmp
double minlat, minlon, maxlat, maxlon;
} Bounds;
std::string GetSafeAttributeString(const tinyxml2::XMLElement* elem, const std::string& name);
double GetSafeAttributeFloat(const tinyxml2::XMLElement* elem, const std::string& name);
uint64_t GetSafeAttributeUint64(const tinyxml2::XMLElement* elem, const std::string& name);
bool GetSafeAttributeBool(const tinyxml2::XMLElement* elem, const std::string& name);
[[nodiscard]] std::string GetSafeAttributeString(const tinyxml2::XMLElement* elem, const std::string& name);
[[nodiscard]] double GetSafeAttributeFloat(const tinyxml2::XMLElement* elem, const std::string& name);
[[nodiscard]] uint64_t GetSafeAttributeUint64(const tinyxml2::XMLElement* elem, const std::string& name);
[[nodiscard]] bool GetSafeAttributeBool(const tinyxml2::XMLElement* elem, const std::string& name);
}

View file

@ -18,256 +18,95 @@ struct TriangulationData {
std::vector<int> segments;
};
struct Ring {
std::vector<osmp::Relation::Member> members;
int ring;
};
// Map values from one interval [A, B] to another [a, b]
inline double Map(double A, double B, double a, double b, double x)
{
return (x - A) * (b - a) / (B - A) + a;
}
// TODO: Implement better algorithm
bool SelfIntersecting(const Ring & ring)
{
struct Segment {
std::shared_ptr<osmp::Node> p1, p2;
};
// Get all segments
std::vector<Segment> segments;
for (const osmp::Relation::Member member : ring.members)
{
std::vector<std::shared_ptr<osmp::Node>> nodes = std::dynamic_pointer_cast<osmp::Way>(member.member)->GetNodes();
for (auto it = nodes.begin(); it != nodes.end() - 1; it++)
{
segments.push_back({
*it, *(it + 1)
});
}
}
// Check for self intersection (O(n^2)...)
for (auto it = segments.begin(); it != segments.end(); it++)
{
for (auto jt = segments.begin(); jt != segments.end(); jt++)
{
if (it == jt) continue;
double A1 = (it->p1->lat - it->p2->lat) / (it->p1->lon - it->p2->lon);
double A2 = (jt->p1->lat - jt->p2->lat) / (jt->p1->lon - jt->p2->lon);
if (A1 == A2) // Parallel
continue;
double b1 = it->p1->lat - A1 * it->p1->lon;
double b2 = jt->p1->lat - A2 * jt->p1->lon;
double Xa = (b2 - b1) / (A1 - A2);
double Ya = A1 * Xa + b1;
if ((Xa < std::max(std::min(it->p1->lon, it->p2->lon), std::min(jt->p1->lon, jt->p2->lon))) ||
(Xa > std::min(std::max(it->p1->lon, it->p2->lon), std::max(jt->p1->lon, jt->p2->lon))))
continue;
else
return true;
}
}
return false;
}
Multipolygon::Multipolygon(const std::shared_ptr<osmp::Relation>& relation, int width, int height, osmp::Bounds bounds) :
r(255), g(0), b(255), visible(true), rendering(RenderType::FILL), id(relation->id)
{
if (relation->HasNullMembers())
return;
// BREAKIF(7344428);
// BREAKIF(6427823);
const std::vector<osmp::Relation::Member>& members = relation->GetWays();
std::vector<TriangulationData> data;
// Implement https://wiki.openstreetmap.org/wiki/Relation:multipolygon/Algorithm
// Ring assignment
std::vector<osmp::Relation::Member> ways = relation->GetWays();
std::vector<std::shared_ptr<osmp::Node>> nodes;
int run = 1;
// RA-1
std::vector<Ring> rings;
int ringCount = 0;
bool lastWasInner = false;
bool hasSeenOuter = false;
std::vector<std::vector<osmp::Relation::Member>> outerWays;
std::vector<std::vector<osmp::Relation::Member>> innerWays;
// Pre processing
for (osmp::Relation::Member member : ways) {
std::shared_ptr<osmp::Way> way = std::dynamic_pointer_cast<osmp::Way>(member.member);
if (member.role == "inner")
// RA-2
rings.push_back({ {members[0]}, ringCount });
// RA-3
if (rings[ringCount].members.front().member == rings[ringCount].members.back().member)
{
if (SelfIntersecting(rings[ringCount]))
{
if (!hasSeenOuter) // TODO: Find better way to sort things
continue;
if (innerWays.empty() || !lastWasInner)
innerWays.push_back({});
innerWays.back().push_back(member);
lastWasInner = true;
}
else
{
hasSeenOuter = true;
if (outerWays.empty() || lastWasInner)
outerWays.push_back({});
outerWays.back().push_back(member);
lastWasInner = false;
// Backtracking ??
}
}
if (outerWays.empty()) // There must always be an outer ring, anything else makes no sense
return;
auto jt = outerWays.begin();
bool currentIsInner = false;
while (!outerWays.empty() || !innerWays.empty())
else // RA-4
{
std::vector<osmp::Relation::Member> member = *jt;
auto it = member.begin();
while (!member.empty())
{
if (it == member.end())
it = member.begin();
std::shared_ptr<osmp::Way> way = std::dynamic_pointer_cast<osmp::Way>(it->member);
// Several possible scenarios:
// Closed way
// Outer edge
// Append all nodes to the triangulation data
// Inner edge
// Append all nodes to the triangulation data
// Calculate average of nodes to get coordinates of the hole
//
// Open way
// Read next way until way is closed. This MUST happen, if the way remains open the OSM data is faulty and should be discarded
// Continue with Closed way algorithm
bool inner = (it->role == "inner");
std::vector<std::shared_ptr<osmp::Node>> wayNodes = way->GetNodes();
if (run == 1) {
nodes.insert(nodes.begin(), wayNodes.begin(), wayNodes.end());
}
else {
if (nodes.back() == wayNodes.front()) {
nodes.insert(nodes.end(), wayNodes.begin() + 1, wayNodes.end());
}
else if (nodes.back() == wayNodes.back()) {
nodes.insert(nodes.end(), wayNodes.rbegin() + 1, wayNodes.rend());
}
else if (nodes.front() == wayNodes.back()) {
nodes.insert(nodes.begin(), wayNodes.begin(), wayNodes.end() - 1);
}
else if (nodes.front() == wayNodes.front()) {
nodes.insert(nodes.begin(), wayNodes.rbegin(), wayNodes.rend() - 1);
}
else {
it++;
continue;
}
}
it = member.erase(it);
run++;
if (!(way->closed)) {
if (nodes.size() > 1 && nodes.front() == nodes.back())
{
// nodes.pop_back();
}
else
{
continue;
}
}
nodes.pop_back();
if (!inner || data.empty())
{
data.push_back({});
}
TriangulationData& td = data.back();
// Push all vertices to data
std::vector<REAL> vertices;
std::map<int, int> duplicates;
int n = td.vertices.size() / 2;
for (const std::shared_ptr<osmp::Node>& node : nodes) {
double x = Map(bounds.minlon, bounds.maxlon, 0, width, node->lon);
double y = height - Map(bounds.minlat, bounds.maxlat, 0, height, node->lat);
auto xit = std::find(td.vertices.begin(), td.vertices.end(), x);
auto yit = std::find(td.vertices.begin(), td.vertices.end(), y);
if (std::distance(xit, yit) == 1) {
duplicates.insert(std::make_pair(n, std::distance(td.vertices.begin(), xit) / 2));
}
else {
vertices.push_back(x);
vertices.push_back(y);
}
n++;
}
if (inner)
{
// Calculate data of hole by using the average position of all inner vertices (that should work right?, probably not...)
REAL holeX = 0.0f;
REAL holeY = 0.0f;;
for (int i = 0; i < vertices.size(); i += 2)
{
holeX += vertices[i];
holeY += vertices[i + 1];
}
holeX /= (vertices.size() / 2);
holeY /= (vertices.size() / 2);
td.holes.push_back(holeX);
td.holes.push_back(holeY);
}
// Get segments
int segNum = td.vertices.size() / 2;
for (int i = 0; i < vertices.size(); i += 2) {
auto dit = duplicates.find(segNum);
if (dit != duplicates.end())
{
td.segments.push_back(dit->second);
}
else
{
td.segments.push_back(segNum++);
}
dit = duplicates.find(segNum);
if (dit != duplicates.end())
{
td.segments.push_back(dit->second);
}
else
{
td.segments.push_back(segNum);
}
}
td.segments.back() = td.vertices.size() / 2;
td.vertices.insert(td.vertices.end(), vertices.begin(), vertices.end());
nodes.clear();
run = 1;
}
if (currentIsInner) {
innerWays.erase(innerWays.begin());
jt = outerWays.begin();
}
else {
outerWays.erase(outerWays.begin());
jt = innerWays.begin();
}
currentIsInner = !currentIsInner;
}
char* triswitches = "zpNBQ";
for (TriangulationData& td : data)
{
triangulateio in;
in.numberofpoints = td.vertices.size() / 2;
in.pointlist = td.vertices.data();
in.pointmarkerlist = NULL;
in.numberofpointattributes = 0;
in.numberofpointattributes = NULL;
in.numberofholes = td.holes.size() / 2;
in.holelist = td.holes.data();
in.numberofsegments = td.segments.size() / 2;
in.segmentlist = td.segments.data();
in.segmentmarkerlist = NULL;
in.numberofregions = 0;
in.regionlist = NULL;
triangulateio out;
out.pointlist = NULL;
out.pointmarkerlist = NULL;
out.trianglelist = NULL;
out.segmentlist = NULL;
out.segmentmarkerlist = NULL;
triangulate(triswitches, &in, &out, NULL);
// TODO: memory leak go brrrr
polygons.push_back({});
for (int i = 0; i < in.numberofpoints * 2; i += 2) {
polygons.back().vertices.push_back({ in.pointlist[i], in.pointlist[i + 1] });
// polygons.back().vertices.push_back(in.pointlist[i + 1]);
}
for (int i = 0; i < out.numberoftriangles * 3; i++) {
polygons.back().indices.push_back(out.trianglelist[i]);
}
for (int i = 0; i < in.numberofsegments * 2; i++) {
polygons.back().segments.push_back(in.segmentlist[i]);
}
trifree(out.trianglelist);
trifree(out.segmentlist);
}