commit
0bda0c5484
5
.gitignore
vendored
5
.gitignore
vendored
|
@ -9,6 +9,7 @@
|
||||||
*.user
|
*.user
|
||||||
*.userosscache
|
*.userosscache
|
||||||
*.sln.docstates
|
*.sln.docstates
|
||||||
|
*.json
|
||||||
|
|
||||||
# User-specific files (MonoDevelop/Xamarin Studio)
|
# User-specific files (MonoDevelop/Xamarin Studio)
|
||||||
*.userprefs
|
*.userprefs
|
||||||
|
@ -360,4 +361,6 @@ MigrationBackup/
|
||||||
.ionide/
|
.ionide/
|
||||||
|
|
||||||
# Fody - auto-generated XML schema
|
# Fody - auto-generated XML schema
|
||||||
FodyWeavers.xsd
|
FodyWeavers.xsd
|
||||||
|
|
||||||
|
res/bigleipzig.osm
|
|
@ -6,9 +6,11 @@ cmake_minimum_required (VERSION 3.8)
|
||||||
project ("MapViewer")
|
project ("MapViewer")
|
||||||
|
|
||||||
find_package(SDL2 CONFIG REQUIRED)
|
find_package(SDL2 CONFIG REQUIRED)
|
||||||
|
find_package(SDL2-GFX CONFIG REQUIRED)
|
||||||
|
|
||||||
# Include sub-projects.
|
# Include sub-projects.
|
||||||
add_subdirectory ("lib/osmparser")
|
add_subdirectory ("lib/osmparser")
|
||||||
|
add_subdirectory ("lib/triangle")
|
||||||
|
|
||||||
file(GLOB_RECURSE SOURCE_FILES
|
file(GLOB_RECURSE SOURCE_FILES
|
||||||
"src/*.cpp"
|
"src/*.cpp"
|
||||||
|
@ -24,15 +26,19 @@ add_executable(mapviewer
|
||||||
|
|
||||||
target_include_directories(mapviewer PRIVATE
|
target_include_directories(mapviewer PRIVATE
|
||||||
osmp
|
osmp
|
||||||
SDL2::SDL2
|
triangle
|
||||||
|
SDL2::SDL2 SDL2::SDL2_gfx
|
||||||
)
|
)
|
||||||
|
|
||||||
target_link_libraries(mapviewer PRIVATE
|
target_link_libraries(mapviewer PRIVATE
|
||||||
osmp
|
osmp
|
||||||
SDL2::SDL2 SDL2::SDL2main
|
triangle
|
||||||
|
SDL2::SDL2 SDL2::SDL2main SDL2::SDL2_gfx
|
||||||
)
|
)
|
||||||
|
|
||||||
add_custom_command(TARGET mapviewer POST_BUILD
|
add_custom_command(TARGET mapviewer POST_BUILD
|
||||||
COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_SOURCE_DIR}/res/map.osm $<TARGET_FILE_DIR:mapviewer>
|
COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_SOURCE_DIR}/res/map.osm $<TARGET_FILE_DIR:mapviewer>
|
||||||
COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_SOURCE_DIR}/res/bigmap.osm $<TARGET_FILE_DIR:mapviewer>
|
COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_SOURCE_DIR}/res/bigmap.osm $<TARGET_FILE_DIR:mapviewer>
|
||||||
|
COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_SOURCE_DIR}/res/leipzig.osm $<TARGET_FILE_DIR:mapviewer>
|
||||||
|
COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_SOURCE_DIR}/res/jp.osm $<TARGET_FILE_DIR:mapviewer>
|
||||||
)
|
)
|
42
include/multipolygon.hpp
Normal file
42
include/multipolygon.hpp
Normal file
|
@ -0,0 +1,42 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <memory>
|
||||||
|
|
||||||
|
#include <osmrelation.hpp>
|
||||||
|
|
||||||
|
struct SDL_FPoint;
|
||||||
|
struct SDL_Renderer;
|
||||||
|
|
||||||
|
class Multipolygon
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
Multipolygon(const std::shared_ptr<osmp::Relation>& relation, int width, int height, osmp::Bounds bounds);
|
||||||
|
|
||||||
|
void SetColor(int r, int g, int b);
|
||||||
|
void Draw(SDL_Renderer* renderer);
|
||||||
|
|
||||||
|
bool operator < (const Multipolygon& other) const {
|
||||||
|
return (rendering < other.rendering);
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
struct Vertex {
|
||||||
|
double x, y;
|
||||||
|
};
|
||||||
|
struct Polygon {
|
||||||
|
std::vector<Vertex> vertices;
|
||||||
|
std::vector<int> indices;
|
||||||
|
std::vector<int> segments;
|
||||||
|
};
|
||||||
|
|
||||||
|
std::vector<Polygon> polygons;
|
||||||
|
int r;
|
||||||
|
int g;
|
||||||
|
int b;
|
||||||
|
bool visible;
|
||||||
|
enum RenderType {
|
||||||
|
FILL,
|
||||||
|
OUTLINE,
|
||||||
|
INDOOR
|
||||||
|
} rendering;
|
||||||
|
};
|
|
@ -1,7 +1,5 @@
|
||||||
cmake_minimum_required(VERSION 3.10)
|
cmake_minimum_required(VERSION 3.10)
|
||||||
|
|
||||||
project(osmp)
|
|
||||||
|
|
||||||
find_package(tinyxml2 CONFIG REQUIRED)
|
find_package(tinyxml2 CONFIG REQUIRED)
|
||||||
|
|
||||||
file(GLOB_RECURSE CPP_FILES
|
file(GLOB_RECURSE CPP_FILES
|
||||||
|
@ -15,7 +13,7 @@ file(GLOB_RECURSE HPP_FILES
|
||||||
get_target_property(TINYXML2_INCLUDE_DIR tinyxml2::tinyxml2 INTERFACE_INCLUDE_DIRECTORIES)
|
get_target_property(TINYXML2_INCLUDE_DIR tinyxml2::tinyxml2 INTERFACE_INCLUDE_DIRECTORIES)
|
||||||
|
|
||||||
add_library(osmp STATIC
|
add_library(osmp STATIC
|
||||||
${CPP_FILES} ${HPP_FILES}
|
${CPP_FILES}
|
||||||
)
|
)
|
||||||
|
|
||||||
target_include_directories(osmp PUBLIC
|
target_include_directories(osmp PUBLIC
|
||||||
|
|
51
lib/osmparser/include/osmimember.hpp
Normal file
51
lib/osmparser/include/osmimember.hpp
Normal file
|
@ -0,0 +1,51 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
#include <vector>
|
||||||
|
#include <map>
|
||||||
|
|
||||||
|
#include <util.hpp>
|
||||||
|
#include <osmtag.hpp>
|
||||||
|
|
||||||
|
namespace osmp
|
||||||
|
{
|
||||||
|
class Object;
|
||||||
|
|
||||||
|
class IMember
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
enum class Type {
|
||||||
|
NODE, WAY, RELATION
|
||||||
|
};
|
||||||
|
|
||||||
|
public:
|
||||||
|
IMember(const IMember& other) = delete;
|
||||||
|
virtual ~IMember() {}
|
||||||
|
|
||||||
|
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;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
IMember(const tinyxml2::XMLElement* element, Object* parent, IMember::Type type);
|
||||||
|
|
||||||
|
protected:
|
||||||
|
IMember::Type type;
|
||||||
|
Object* parent;
|
||||||
|
|
||||||
|
std::vector<Tag> tags;
|
||||||
|
// std::map<std::string, std::string> tags;
|
||||||
|
|
||||||
|
public:
|
||||||
|
uint64_t id;
|
||||||
|
std::string user;
|
||||||
|
unsigned int uid;
|
||||||
|
bool visible;
|
||||||
|
std::string version;
|
||||||
|
unsigned int changeset;
|
||||||
|
std::string timestamp;
|
||||||
|
};
|
||||||
|
}
|
|
@ -2,33 +2,19 @@
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
#include "util.hpp"
|
#include "util.hpp"
|
||||||
|
#include <osmimember.hpp>
|
||||||
|
#include <osmtag.hpp>
|
||||||
|
|
||||||
namespace osmp
|
namespace osmp
|
||||||
{
|
{
|
||||||
class Object;
|
class Object;
|
||||||
|
|
||||||
class Node
|
class Node : public IMember
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
Node(const tinyxml2::XMLElement* xml, Object* parent);
|
Node(const tinyxml2::XMLElement* xml, Object* parent);
|
||||||
|
|
||||||
const std::vector<Tag>& GetTags() const;
|
|
||||||
size_t GetTagsSize() const;
|
|
||||||
const Tag& GetTag(size_t index) const;
|
|
||||||
|
|
||||||
private:
|
|
||||||
Object* parent;
|
|
||||||
|
|
||||||
std::vector<Tag> tags;
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
unsigned int id;
|
double lat, lon;
|
||||||
float lat, lon;
|
|
||||||
std::string user;
|
|
||||||
unsigned int uid;
|
|
||||||
bool visible;
|
|
||||||
std::string version;
|
|
||||||
unsigned int changeset;
|
|
||||||
std::string timestamp;
|
|
||||||
};
|
};
|
||||||
}
|
}
|
|
@ -1,5 +1,6 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
#include <string>
|
#include <string>
|
||||||
|
#include <memory>
|
||||||
#include <map>
|
#include <map>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
|
@ -9,6 +10,7 @@ namespace osmp
|
||||||
{
|
{
|
||||||
class Node;
|
class Node;
|
||||||
class Way;
|
class Way;
|
||||||
|
class Relation;
|
||||||
|
|
||||||
class Object
|
class Object
|
||||||
{
|
{
|
||||||
|
@ -16,13 +18,17 @@ namespace osmp
|
||||||
Object(const std::string& file);
|
Object(const std::string& file);
|
||||||
~Object();
|
~Object();
|
||||||
|
|
||||||
std::vector<Node*> GetNodes() const;
|
std::vector<std::shared_ptr<Node>> GetNodes() const;
|
||||||
size_t GetNodesSize() const;
|
size_t GetNodesSize() const;
|
||||||
const Node* GetNode(unsigned int id) const;
|
std::shared_ptr<Node> GetNode(uint64_t id) const;
|
||||||
|
|
||||||
std::vector<Way*> GetWays() const;
|
std::vector<std::shared_ptr<Way>> GetWays() const;
|
||||||
size_t GetWaysSize() const;
|
size_t GetWaysSize() const;
|
||||||
const Way* GetWay(unsigned int id) const;
|
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;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
const std::string version;
|
const std::string version;
|
||||||
|
@ -31,7 +37,8 @@ namespace osmp
|
||||||
Bounds bounds;
|
Bounds bounds;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
std::map<unsigned int, Node*> nodes;
|
std::map<uint64_t, std::shared_ptr<Node>> nodes;
|
||||||
std::map<unsigned int, Way*> ways;
|
std::map<uint64_t, std::shared_ptr<Way>> ways;
|
||||||
|
std::map<uint64_t, std::shared_ptr<Relation>> relations;
|
||||||
};
|
};
|
||||||
}
|
}
|
|
@ -2,4 +2,7 @@
|
||||||
|
|
||||||
#include <osmobject.hpp>
|
#include <osmobject.hpp>
|
||||||
#include <osmnode.hpp>
|
#include <osmnode.hpp>
|
||||||
#include <osmway.hpp>
|
#include <osmway.hpp>
|
||||||
|
#include <osmtag.hpp>
|
||||||
|
#include <osmrelation.hpp>
|
||||||
|
#include <osmimember.hpp>
|
43
lib/osmparser/include/osmrelation.hpp
Normal file
43
lib/osmparser/include/osmrelation.hpp
Normal file
|
@ -0,0 +1,43 @@
|
||||||
|
#pragma once
|
||||||
|
#include <vector>
|
||||||
|
#include <memory>
|
||||||
|
|
||||||
|
#include <util.hpp>
|
||||||
|
#include <osmtag.hpp>
|
||||||
|
#include <osmimember.hpp>
|
||||||
|
|
||||||
|
namespace osmp
|
||||||
|
{
|
||||||
|
class Object;
|
||||||
|
|
||||||
|
class Relation : public IMember
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
typedef struct sMember {
|
||||||
|
std::shared_ptr<IMember> member;
|
||||||
|
std::string role;
|
||||||
|
} Member;
|
||||||
|
|
||||||
|
public:
|
||||||
|
Relation(const tinyxml2::XMLElement* xml, Object* parent);
|
||||||
|
|
||||||
|
std::string GetRelationType();
|
||||||
|
|
||||||
|
const std::vector<Member>& GetNodes() const;
|
||||||
|
size_t GetNodesSize() const;
|
||||||
|
const Member& GetNode(size_t index) const;
|
||||||
|
|
||||||
|
const std::vector<Member>& GetWays() const;
|
||||||
|
size_t GetWaysSize() const;
|
||||||
|
const Member& GetWay(size_t index) const;
|
||||||
|
|
||||||
|
bool HasNullMembers() const { return hasNullMembers; }
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::string relationType;
|
||||||
|
bool hasNullMembers;
|
||||||
|
|
||||||
|
std::vector<Member> nodes;
|
||||||
|
std::vector<Member> ways;
|
||||||
|
};
|
||||||
|
}
|
36
lib/osmparser/include/osmtag.hpp
Normal file
36
lib/osmparser/include/osmtag.hpp
Normal file
|
@ -0,0 +1,36 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
namespace osmp
|
||||||
|
{
|
||||||
|
enum class TagKey {
|
||||||
|
NONE,
|
||||||
|
AERIALWAY, AEROWAY, AMENITY, BARRIER, BOUNDARY,
|
||||||
|
BUILDING, CRAFT, EMERGENCY, GEOLOGICAL, HEALTHCARE,
|
||||||
|
HIGHWAY, HISTORIC, LANDUSE, LEISURE, MANMADE, MILITARY,
|
||||||
|
NATURAL, OFFICE, PLACE, POWER, PUBLIC_TRANSPORT,
|
||||||
|
RAILWAY, ROUTE, SHOP, SPORT, TELECOM, TOURISM, WATER, WATERWAY
|
||||||
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
enum class TagValue {
|
||||||
|
NONE,
|
||||||
|
|
||||||
|
BUILDING_APARTMENTS, BUILDING_BUNGALOW, BUILDING_CABIN, BUILDING_DETACHED, BUILDING_DORMITORY, BUILDING_FARM, BUILDING_GER,
|
||||||
|
BUILDING_HOTEL, BUILDING_HOUSE, BUILDING_HOUSEBOAT, BUILDING_RESIDENTIAL, BUILDING_SEMIDETACHED_HOUSE, BUILDING_STATIC_CARAVAN,
|
||||||
|
BUILDING_TERRACE, BUILDING_COMMERCIAL, BUILDING_INDUSTRIAL, BUILDING_KIOSK, BUILDING_OFFICE, BUILDING_RETAIL, BUILDING_SUPERMARKET,
|
||||||
|
BUILDING_WAREHOUSE, BUILDING_CATHEDRAL, BUILDING_CHAPEL, BUILDING_CHURCH, BUILDING_MONASTERY, BUILDING_MOSQUE, BUILDING_PRESBYTERY,
|
||||||
|
BUILDING_RELIGIOUS, BUILDING_SHRINE, BUILDING_SYNAGOGUE, BUILDING_TEMPLE, BUILDING_BAKEHOUSE, BUILDING_CIVIC, BUILDING_FIRE_STATION,
|
||||||
|
BUILDING_GOVERNMENT, BUILDING_HOSPITAL, BUILDING_PUBLIC, BUILDING_TOILETS, BUILDING_TRAIN_STATION, BUILDING_TRANSPORTATION,
|
||||||
|
BUILDING_KINDERGARTEN, BUILDING_SCHOOL, BUILDING_UNIVERSITY
|
||||||
|
|
||||||
|
};
|
||||||
|
*/
|
||||||
|
|
||||||
|
typedef struct sTag
|
||||||
|
{
|
||||||
|
std::string k; // TODO: Should/could be an enum
|
||||||
|
std::string v;
|
||||||
|
} Tag;
|
||||||
|
}
|
|
@ -1,39 +1,29 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
#include <memory>
|
||||||
|
|
||||||
#include <util.hpp>
|
#include <util.hpp>
|
||||||
|
#include <osmtag.hpp>
|
||||||
|
#include <osmimember.hpp>
|
||||||
|
|
||||||
namespace osmp
|
namespace osmp
|
||||||
{
|
{
|
||||||
class Object;
|
class Object;
|
||||||
class Node;
|
class Node;
|
||||||
|
|
||||||
class Way
|
class Way : public IMember
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
Way(const tinyxml2::XMLElement* way_elem, Object* parent);
|
Way(const tinyxml2::XMLElement* way_elem, Object* parent);
|
||||||
|
|
||||||
const std::vector<Tag>& GetTags() const;
|
const std::vector<std::shared_ptr<Node>>& GetNodes() const;
|
||||||
size_t GetTagsSize() const;
|
|
||||||
const Tag& GetTag(size_t index) const;
|
|
||||||
|
|
||||||
const std::vector<const Node*>& GetNodes() const;
|
|
||||||
size_t GetNodesSize() const;
|
size_t GetNodesSize() const;
|
||||||
const Node& GetNode(size_t index) const;
|
const std::shared_ptr<Node>& GetNode(size_t index) const;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
unsigned int id;
|
bool area, closed; // Closed := Startpoint = endpoint, Area := Closed AND certain conditions are not met
|
||||||
std::string user;
|
|
||||||
unsigned int uid;
|
|
||||||
bool visible;
|
|
||||||
std::string version;
|
|
||||||
unsigned int changeset;
|
|
||||||
std::string timestamp;
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
Object* parent;
|
std::vector<std::shared_ptr<Node>> nodes;
|
||||||
|
|
||||||
std::vector<const Node*> nodes;
|
|
||||||
std::vector<Tag> tags;
|
|
||||||
};
|
};
|
||||||
}
|
}
|
|
@ -11,17 +11,11 @@ namespace osmp
|
||||||
{
|
{
|
||||||
typedef struct sBounds
|
typedef struct sBounds
|
||||||
{
|
{
|
||||||
float minlat, minlon, maxlat, maxlon;
|
double minlat, minlon, maxlat, maxlon;
|
||||||
} Bounds;
|
} Bounds;
|
||||||
|
|
||||||
typedef struct sTag
|
|
||||||
{
|
|
||||||
std::string k; // TODO: Should/could be an enum
|
|
||||||
std::string v;
|
|
||||||
} Tag;
|
|
||||||
|
|
||||||
std::string GetSafeAttributeString(const tinyxml2::XMLElement* elem, const std::string& name);
|
std::string GetSafeAttributeString(const tinyxml2::XMLElement* elem, const std::string& name);
|
||||||
float GetSafeAttributeFloat(const tinyxml2::XMLElement* elem, const std::string& name);
|
double GetSafeAttributeFloat(const tinyxml2::XMLElement* elem, const std::string& name);
|
||||||
unsigned int GetSafeAttributeUint(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);
|
bool GetSafeAttributeBool(const tinyxml2::XMLElement* elem, const std::string& name);
|
||||||
}
|
}
|
66
lib/osmparser/src/osmimember.cpp
Normal file
66
lib/osmparser/src/osmimember.cpp
Normal file
|
@ -0,0 +1,66 @@
|
||||||
|
#include <osmimember.hpp>
|
||||||
|
|
||||||
|
#include <osmobject.hpp>
|
||||||
|
#include <tinyxml2.h>
|
||||||
|
|
||||||
|
namespace xml = tinyxml2;
|
||||||
|
|
||||||
|
namespace osmp
|
||||||
|
{
|
||||||
|
IMember::IMember(const xml::XMLElement* element, Object* parent, IMember::Type type) :
|
||||||
|
type(type), parent(parent)
|
||||||
|
{
|
||||||
|
// Get Attribute
|
||||||
|
id = GetSafeAttributeUint64(element, "id");
|
||||||
|
user = GetSafeAttributeString(element, "user");
|
||||||
|
uid = GetSafeAttributeUint64(element, "uid");
|
||||||
|
visible = GetSafeAttributeBool(element, "visible");
|
||||||
|
version = GetSafeAttributeString(element, "version");
|
||||||
|
changeset = GetSafeAttributeUint64(element, "changeset");
|
||||||
|
timestamp = GetSafeAttributeString(element, "timestamp");
|
||||||
|
|
||||||
|
const xml::XMLElement* tag_element = element->FirstChildElement("tag");
|
||||||
|
while (tag_element != nullptr)
|
||||||
|
{
|
||||||
|
tags.push_back({
|
||||||
|
GetSafeAttributeString(tag_element, "k"),
|
||||||
|
GetSafeAttributeString(tag_element, "v"),
|
||||||
|
});
|
||||||
|
|
||||||
|
tag_element = tag_element->NextSiblingElement("tag");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
IMember::Type IMember::GetType() const
|
||||||
|
{
|
||||||
|
return type;
|
||||||
|
}
|
||||||
|
|
||||||
|
const std::vector<Tag>& IMember::GetTags() const
|
||||||
|
{
|
||||||
|
return tags;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t IMember::GetTagsSize() const
|
||||||
|
{
|
||||||
|
return tags.size();
|
||||||
|
}
|
||||||
|
|
||||||
|
const Tag& IMember::GetTag(size_t index) const
|
||||||
|
{
|
||||||
|
return tags[index];
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string IMember::GetTag(const std::string& key) const
|
||||||
|
{
|
||||||
|
for (const Tag& tag : tags)
|
||||||
|
{
|
||||||
|
if (tag.k == key)
|
||||||
|
{
|
||||||
|
return tag.v;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
}
|
|
@ -7,43 +7,10 @@ namespace xml = tinyxml2;
|
||||||
namespace osmp
|
namespace osmp
|
||||||
{
|
{
|
||||||
Node::Node(const tinyxml2::XMLElement* node_elem, Object* parent) :
|
Node::Node(const tinyxml2::XMLElement* node_elem, Object* parent) :
|
||||||
parent(parent)
|
IMember(node_elem, parent, IMember::Type::NODE)
|
||||||
{
|
{
|
||||||
// Get Attribute
|
// Get Attribute
|
||||||
id = GetSafeAttributeUint(node_elem, "id");
|
|
||||||
lat = GetSafeAttributeFloat(node_elem, "lat");
|
lat = GetSafeAttributeFloat(node_elem, "lat");
|
||||||
lon = GetSafeAttributeFloat(node_elem, "lon");
|
lon = GetSafeAttributeFloat(node_elem, "lon");
|
||||||
user = GetSafeAttributeString(node_elem, "user");
|
|
||||||
uid = GetSafeAttributeUint(node_elem, "uid");
|
|
||||||
visible = GetSafeAttributeBool(node_elem, "visible");
|
|
||||||
version = GetSafeAttributeString(node_elem, "version");
|
|
||||||
changeset = GetSafeAttributeUint(node_elem, "changeset");
|
|
||||||
timestamp = GetSafeAttributeString(node_elem, "timestamp");
|
|
||||||
|
|
||||||
const xml::XMLElement* tag_element = node_elem->FirstChildElement("tag");
|
|
||||||
while (tag_element != nullptr)
|
|
||||||
{
|
|
||||||
tags.push_back({
|
|
||||||
GetSafeAttributeString(tag_element, "k"),
|
|
||||||
GetSafeAttributeString(tag_element, "v")
|
|
||||||
});
|
|
||||||
|
|
||||||
tag_element = tag_element->NextSiblingElement("tag");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const std::vector<Tag>& Node::GetTags() const
|
|
||||||
{
|
|
||||||
return tags;
|
|
||||||
}
|
|
||||||
|
|
||||||
size_t Node::GetTagsSize() const
|
|
||||||
{
|
|
||||||
return tags.size();
|
|
||||||
}
|
|
||||||
|
|
||||||
const Tag& Node::GetTag(size_t index) const
|
|
||||||
{
|
|
||||||
return tags[index];
|
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -7,6 +7,7 @@
|
||||||
|
|
||||||
#include <osmnode.hpp>
|
#include <osmnode.hpp>
|
||||||
#include <osmway.hpp>
|
#include <osmway.hpp>
|
||||||
|
#include <osmrelation.hpp>
|
||||||
|
|
||||||
namespace xml = tinyxml2;
|
namespace xml = tinyxml2;
|
||||||
|
|
||||||
|
@ -38,7 +39,7 @@ namespace osmp
|
||||||
xml::XMLElement* node_elem = root->FirstChildElement("node");
|
xml::XMLElement* node_elem = root->FirstChildElement("node");
|
||||||
while (node_elem != nullptr)
|
while (node_elem != nullptr)
|
||||||
{
|
{
|
||||||
Node* new_node = new Node(node_elem, this);
|
std::shared_ptr<Node> new_node = std::make_shared<Node>(node_elem, this);
|
||||||
nodes.insert(std::make_pair(new_node->id, new_node));
|
nodes.insert(std::make_pair(new_node->id, new_node));
|
||||||
|
|
||||||
node_elem = node_elem->NextSiblingElement("node");
|
node_elem = node_elem->NextSiblingElement("node");
|
||||||
|
@ -48,32 +49,32 @@ namespace osmp
|
||||||
xml::XMLElement* way_elem = root->FirstChildElement("way");
|
xml::XMLElement* way_elem = root->FirstChildElement("way");
|
||||||
while (way_elem != nullptr)
|
while (way_elem != nullptr)
|
||||||
{
|
{
|
||||||
Way* new_way = new Way(way_elem, this);
|
std::shared_ptr<Way> new_way = std::make_shared<Way>(way_elem, this);
|
||||||
ways.insert(std::make_pair(new_way->id, new_way));
|
ways.insert(std::make_pair(new_way->id, new_way));
|
||||||
|
|
||||||
way_elem = way_elem->NextSiblingElement("way");
|
way_elem = way_elem->NextSiblingElement("way");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Get relations
|
||||||
|
xml::XMLElement* relation_elem = root->FirstChildElement("relation");
|
||||||
|
while (relation_elem != nullptr)
|
||||||
|
{
|
||||||
|
std::shared_ptr<Relation> new_way = std::make_shared<Relation>(relation_elem, this);
|
||||||
|
relations.insert(std::make_pair(new_way->id, new_way));
|
||||||
|
|
||||||
|
relation_elem = relation_elem->NextSiblingElement("relation");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Object::~Object()
|
Object::~Object()
|
||||||
{
|
{
|
||||||
for (std::map<unsigned int, Way*>::iterator it = ways.begin(); it != ways.end(); ++it)
|
|
||||||
{
|
|
||||||
delete it->second;
|
|
||||||
}
|
|
||||||
ways.clear();
|
|
||||||
|
|
||||||
for (std::map<unsigned int, Node*>::iterator it = nodes.begin(); it != nodes.end(); ++it)
|
|
||||||
{
|
|
||||||
delete it->second;
|
|
||||||
}
|
|
||||||
nodes.clear();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<Node*> Object::GetNodes() const
|
std::vector<std::shared_ptr<Node>> Object::GetNodes() const
|
||||||
{
|
{
|
||||||
std::vector<Node*> vecNodes;
|
std::vector<std::shared_ptr<Node>> vecNodes;
|
||||||
for (std::map<unsigned int, Node*>::const_iterator it = nodes.begin(); it != nodes.end(); it++)
|
for (std::map<uint64_t, std::shared_ptr<Node>>::const_iterator it = nodes.begin(); it != nodes.end(); it++)
|
||||||
vecNodes.push_back(it->second);
|
vecNodes.push_back(it->second);
|
||||||
|
|
||||||
return vecNodes;
|
return vecNodes;
|
||||||
|
@ -84,19 +85,19 @@ namespace osmp
|
||||||
return nodes.size();
|
return nodes.size();
|
||||||
}
|
}
|
||||||
|
|
||||||
const Node* Object::GetNode(unsigned int id) const
|
std::shared_ptr<Node> Object::GetNode(uint64_t id) const
|
||||||
{
|
{
|
||||||
std::map<unsigned int, Node*>::const_iterator node = nodes.find(id);
|
std::map<uint64_t, std::shared_ptr<Node>>::const_iterator node = nodes.find(id);
|
||||||
if (node != nodes.end())
|
if (node != nodes.end())
|
||||||
return node->second;
|
return node->second;
|
||||||
|
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<Way*> Object::GetWays() const
|
std::vector<std::shared_ptr<Way>> Object::GetWays() const
|
||||||
{
|
{
|
||||||
std::vector<Way*> vecWays;
|
std::vector<std::shared_ptr<Way>> vecWays;
|
||||||
for (std::map<unsigned int, Way*>::const_iterator it = ways.begin(); it != ways.end(); it++)
|
for (std::map<uint64_t, std::shared_ptr<Way>>::const_iterator it = ways.begin(); it != ways.end(); it++)
|
||||||
vecWays.push_back(it->second);
|
vecWays.push_back(it->second);
|
||||||
|
|
||||||
return vecWays;
|
return vecWays;
|
||||||
|
@ -107,12 +108,35 @@ namespace osmp
|
||||||
return ways.size();
|
return ways.size();
|
||||||
}
|
}
|
||||||
|
|
||||||
const Way* Object::GetWay(unsigned int id) const
|
std::shared_ptr<Way> Object::GetWay(uint64_t id) const
|
||||||
{
|
{
|
||||||
std::map<unsigned int, Way*>::const_iterator way = ways.find(id);
|
std::map<uint64_t, std::shared_ptr<Way>>::const_iterator way = ways.find(id);
|
||||||
if (way != ways.end())
|
if (way != ways.end())
|
||||||
return way->second;
|
return way->second;
|
||||||
|
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::vector<std::shared_ptr<Relation>> Object::GetRelations() const
|
||||||
|
{
|
||||||
|
std::vector<std::shared_ptr<Relation>> vecRelations;
|
||||||
|
for (std::map<uint64_t, std::shared_ptr<Relation>>::const_iterator it = relations.begin(); it != relations.end(); it++)
|
||||||
|
vecRelations.push_back(it->second);
|
||||||
|
|
||||||
|
return vecRelations;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t Object::GetRelationsSize() const
|
||||||
|
{
|
||||||
|
return relations.size();
|
||||||
|
}
|
||||||
|
|
||||||
|
std::shared_ptr<Relation> Object::GetRelation(uint64_t id) const
|
||||||
|
{
|
||||||
|
std::map<uint64_t, std::shared_ptr<Relation>>::const_iterator relation = relations.find(id);
|
||||||
|
if (relation != relations.end())
|
||||||
|
return relation->second;
|
||||||
|
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
}
|
}
|
75
lib/osmparser/src/osmrelation.cpp
Normal file
75
lib/osmparser/src/osmrelation.cpp
Normal file
|
@ -0,0 +1,75 @@
|
||||||
|
#include <osmrelation.hpp>
|
||||||
|
|
||||||
|
#include <memory>
|
||||||
|
|
||||||
|
#include <tinyxml2.h>
|
||||||
|
#include <osmobject.hpp>
|
||||||
|
#include <osmnode.hpp>
|
||||||
|
#include <osmway.hpp>
|
||||||
|
|
||||||
|
namespace xml = tinyxml2;
|
||||||
|
|
||||||
|
namespace osmp
|
||||||
|
{
|
||||||
|
Relation::Relation(const xml::XMLElement* xml, Object* parent) :
|
||||||
|
IMember(xml, parent, IMember::Type::RELATION), hasNullMembers(false)
|
||||||
|
{
|
||||||
|
const xml::XMLElement* member_element = xml->FirstChildElement("member");
|
||||||
|
while (member_element != nullptr)
|
||||||
|
{
|
||||||
|
std::string memberType = GetSafeAttributeString(member_element, "type");
|
||||||
|
uint64_t ref = GetSafeAttributeUint64(member_element, "ref");
|
||||||
|
std::string role = GetSafeAttributeString(member_element, "role");
|
||||||
|
|
||||||
|
std::shared_ptr<IMember> member = nullptr;
|
||||||
|
if (memberType == "node") {
|
||||||
|
member = parent->GetNode(ref);
|
||||||
|
nodes.push_back({ member, role });
|
||||||
|
}
|
||||||
|
else if (memberType == "way") {
|
||||||
|
member = parent->GetWay(ref);
|
||||||
|
if (member == nullptr) {
|
||||||
|
hasNullMembers = true;
|
||||||
|
}
|
||||||
|
ways.push_back({ member, role });
|
||||||
|
}
|
||||||
|
|
||||||
|
member_element = member_element->NextSiblingElement("member");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string Relation::GetRelationType()
|
||||||
|
{
|
||||||
|
return GetTag("type");
|
||||||
|
}
|
||||||
|
|
||||||
|
const std::vector<Relation::Member>& Relation::GetNodes() const
|
||||||
|
{
|
||||||
|
return nodes;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t Relation::GetNodesSize() const
|
||||||
|
{
|
||||||
|
return nodes.size();
|
||||||
|
}
|
||||||
|
|
||||||
|
const Relation::Member& Relation::GetNode(size_t index) const
|
||||||
|
{
|
||||||
|
return nodes[index];
|
||||||
|
}
|
||||||
|
|
||||||
|
const std::vector<Relation::Member>& Relation::GetWays() const
|
||||||
|
{
|
||||||
|
return ways;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t Relation::GetWaysSize() const
|
||||||
|
{
|
||||||
|
return ways.size();
|
||||||
|
}
|
||||||
|
|
||||||
|
const Relation::Member& Relation::GetWay(size_t index) const
|
||||||
|
{
|
||||||
|
return ways[index];
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,62 +1,41 @@
|
||||||
#include <osmway.hpp>
|
#include <osmway.hpp>
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
|
||||||
#include <tinyxml2.h>
|
#include <tinyxml2.h>
|
||||||
#include <osmobject.hpp>
|
#include <osmobject.hpp>
|
||||||
|
#include <osmtag.hpp>
|
||||||
|
|
||||||
namespace xml = tinyxml2;
|
namespace xml = tinyxml2;
|
||||||
|
|
||||||
namespace osmp
|
namespace osmp
|
||||||
{
|
{
|
||||||
Way::Way(const tinyxml2::XMLElement* way_elem, Object* parent) :
|
Way::Way(const tinyxml2::XMLElement* way_elem, Object* parent) :
|
||||||
parent(parent)
|
IMember(way_elem, parent, IMember::Type::WAY)
|
||||||
{
|
{
|
||||||
// Attributes
|
area = GetSafeAttributeBool(way_elem, "area");
|
||||||
id = GetSafeAttributeUint(way_elem, "id");
|
closed = false;
|
||||||
user = GetSafeAttributeString(way_elem, "user");
|
|
||||||
uid = GetSafeAttributeUint(way_elem, "uid");
|
|
||||||
visible = GetSafeAttributeBool(way_elem, "visible");
|
|
||||||
version = GetSafeAttributeString(way_elem, "version");
|
|
||||||
changeset = GetSafeAttributeUint(way_elem, "changeset");
|
|
||||||
timestamp = GetSafeAttributeString(way_elem, "timestamp");
|
|
||||||
|
|
||||||
const xml::XMLElement* nd_elem = way_elem->FirstChildElement("nd");
|
const xml::XMLElement* nd_elem = way_elem->FirstChildElement("nd");
|
||||||
while (nd_elem != nullptr)
|
while (nd_elem != nullptr)
|
||||||
{
|
{
|
||||||
nodes.push_back(
|
nodes.push_back(
|
||||||
parent->GetNode(GetSafeAttributeUint(nd_elem, "ref"))
|
parent->GetNode(GetSafeAttributeUint64(nd_elem, "ref"))
|
||||||
);
|
);
|
||||||
|
|
||||||
nd_elem = nd_elem->NextSiblingElement("nd");
|
nd_elem = nd_elem->NextSiblingElement("nd");
|
||||||
}
|
}
|
||||||
|
|
||||||
const xml::XMLElement* tag_elem = way_elem->FirstChildElement("tag");
|
if (nodes.front() == nodes.back())
|
||||||
while (tag_elem != nullptr)
|
|
||||||
{
|
{
|
||||||
tags.push_back({
|
closed = true;
|
||||||
GetSafeAttributeString(tag_elem, "k"),
|
|
||||||
GetSafeAttributeString(tag_elem, "v")
|
|
||||||
});
|
|
||||||
|
|
||||||
tag_elem = tag_elem->NextSiblingElement("tag");
|
if (!area && GetTag("barrier") == "" && GetTag("highway") == "") // this code sucks, it can be done better
|
||||||
|
area = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const std::vector<Tag>& Way::GetTags() const
|
const std::vector<std::shared_ptr<Node>>& Way::GetNodes() const
|
||||||
{
|
|
||||||
return tags;
|
|
||||||
}
|
|
||||||
|
|
||||||
size_t Way::GetTagsSize() const
|
|
||||||
{
|
|
||||||
return tags.size();
|
|
||||||
}
|
|
||||||
|
|
||||||
const Tag& Way::GetTag(size_t index) const
|
|
||||||
{
|
|
||||||
return tags[index];
|
|
||||||
}
|
|
||||||
|
|
||||||
const std::vector<const Node*>& Way::GetNodes() const
|
|
||||||
{
|
{
|
||||||
return nodes;
|
return nodes;
|
||||||
}
|
}
|
||||||
|
@ -66,8 +45,8 @@ namespace osmp
|
||||||
return nodes.size();
|
return nodes.size();
|
||||||
}
|
}
|
||||||
|
|
||||||
const Node& Way::GetNode(size_t index) const
|
const std::shared_ptr<Node>& Way::GetNode(size_t index) const
|
||||||
{
|
{
|
||||||
return *(nodes[index]);
|
return nodes[index];
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -15,34 +15,26 @@ namespace osmp
|
||||||
|
|
||||||
xml::XMLError result = elem->QueryStringAttribute(name.c_str(), &buffer);
|
xml::XMLError result = elem->QueryStringAttribute(name.c_str(), &buffer);
|
||||||
if (FAILED(result))
|
if (FAILED(result))
|
||||||
{
|
|
||||||
std::cerr << "Failed to fetch string attribute \"" << name << "\"" << std::endl;
|
|
||||||
return "";
|
return "";
|
||||||
}
|
|
||||||
|
|
||||||
std::string returnStr(buffer);
|
std::string returnStr(buffer);
|
||||||
return returnStr;
|
return returnStr;
|
||||||
}
|
}
|
||||||
|
|
||||||
float GetSafeAttributeFloat(const tinyxml2::XMLElement* elem, const std::string& name)
|
double GetSafeAttributeFloat(const tinyxml2::XMLElement* elem, const std::string& name)
|
||||||
{
|
{
|
||||||
float returnVal = 0.0f;
|
double returnVal = 0.0f;
|
||||||
|
|
||||||
xml::XMLError result = elem->QueryFloatAttribute(name.c_str(), &returnVal);
|
xml::XMLError result = elem->QueryDoubleAttribute(name.c_str(), &returnVal);
|
||||||
if (FAILED(result))
|
|
||||||
std::cerr << "Failed to fetch float attribute \"" << name << "\"" << std::endl;
|
|
||||||
|
|
||||||
return returnVal;
|
return returnVal;
|
||||||
}
|
}
|
||||||
|
|
||||||
unsigned int GetSafeAttributeUint(const tinyxml2::XMLElement* elem, const std::string& name)
|
uint64_t GetSafeAttributeUint64(const tinyxml2::XMLElement* elem, const std::string& name)
|
||||||
{
|
{
|
||||||
unsigned int returnVal = 0;
|
uint64_t returnVal = 0;
|
||||||
|
|
||||||
xml::XMLError result = elem->QueryUnsignedAttribute(name.c_str(), &returnVal);
|
|
||||||
if (FAILED(result))
|
|
||||||
std::cerr << "Failed to fetch uint attribute \"" << name << "\"" << std::endl;
|
|
||||||
|
|
||||||
|
xml::XMLError result = elem->QueryUnsigned64Attribute(name.c_str(), &returnVal);
|
||||||
return returnVal;
|
return returnVal;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -51,8 +43,6 @@ namespace osmp
|
||||||
bool returnVal = false;
|
bool returnVal = false;
|
||||||
|
|
||||||
xml::XMLError result = elem->QueryBoolAttribute(name.c_str(), &returnVal);
|
xml::XMLError result = elem->QueryBoolAttribute(name.c_str(), &returnVal);
|
||||||
if (FAILED(result))
|
|
||||||
std::cerr << "Failed to fetch bool attribute \"" << name << "\"" << std::endl;
|
|
||||||
|
|
||||||
return returnVal;
|
return returnVal;
|
||||||
}
|
}
|
||||||
|
|
22
lib/triangle/CMakeLists.txt
Normal file
22
lib/triangle/CMakeLists.txt
Normal file
|
@ -0,0 +1,22 @@
|
||||||
|
cmake_minimum_required(VERSION 3.10)
|
||||||
|
|
||||||
|
file(GLOB_RECURSE CPP_FILES
|
||||||
|
"src/*.c"
|
||||||
|
)
|
||||||
|
|
||||||
|
file(GLOB_RECURSE HPP_FILES
|
||||||
|
"include/*.h"
|
||||||
|
)
|
||||||
|
|
||||||
|
SET_SOURCE_FILES_PROPERTIES( ${CPP_FILES} PROPERTIES LANGUAGE CXX )
|
||||||
|
|
||||||
|
add_library(triangle STATIC
|
||||||
|
${CPP_FILES} ${HPP_FILES}
|
||||||
|
)
|
||||||
|
|
||||||
|
target_include_directories(triangle PUBLIC
|
||||||
|
include
|
||||||
|
${TINYXML2_INCLUDE_DIR}
|
||||||
|
)
|
||||||
|
|
||||||
|
target_compile_definitions(triangle PUBLIC NO_TIMER TRILIBRARY REDUCED DCT_ONLY ANSI_DECLARATORS)
|
198
lib/triangle/README
Normal file
198
lib/triangle/README
Normal file
|
@ -0,0 +1,198 @@
|
||||||
|
Triangle
|
||||||
|
A Two-Dimensional Quality Mesh Generator and Delaunay Triangulator.
|
||||||
|
Version 1.6
|
||||||
|
|
||||||
|
Show Me
|
||||||
|
A Display Program for Meshes and More.
|
||||||
|
Version 1.6
|
||||||
|
|
||||||
|
Copyright 1993, 1995, 1997, 1998, 2002, 2005 Jonathan Richard Shewchuk
|
||||||
|
2360 Woolsey #H
|
||||||
|
Berkeley, California 94705-1927
|
||||||
|
Please send bugs and comments to jrs@cs.berkeley.edu
|
||||||
|
|
||||||
|
Created as part of the Quake project (tools for earthquake simulation).
|
||||||
|
Supported in part by NSF Grant CMS-9318163 and an NSERC 1967 Scholarship.
|
||||||
|
There is no warranty whatsoever. Use at your own risk.
|
||||||
|
|
||||||
|
|
||||||
|
Triangle generates exact Delaunay triangulations, constrained Delaunay
|
||||||
|
triangulations, conforming Delaunay triangulations, Voronoi diagrams, and
|
||||||
|
high-quality triangular meshes. The latter can be generated with no small
|
||||||
|
or large angles, and are thus suitable for finite element analysis.
|
||||||
|
Show Me graphically displays the contents of the geometric files used by
|
||||||
|
Triangle. Show Me can also write images in PostScript form.
|
||||||
|
|
||||||
|
Information on the algorithms used by Triangle, including complete
|
||||||
|
references, can be found in the comments at the beginning of the triangle.c
|
||||||
|
source file. Another listing of these references, with PostScript copies
|
||||||
|
of some of the papers, is available from the Web page
|
||||||
|
|
||||||
|
http://www.cs.cmu.edu/~quake/triangle.research.html
|
||||||
|
|
||||||
|
------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
These programs may be freely redistributed under the condition that the
|
||||||
|
copyright notices (including the copy of this notice in the code comments
|
||||||
|
and the copyright notice printed when the `-h' switch is selected) are
|
||||||
|
not removed, and no compensation is received. Private, research, and
|
||||||
|
institutional use is free. You may distribute modified versions of this
|
||||||
|
code UNDER THE CONDITION THAT THIS CODE AND ANY MODIFICATIONS MADE TO IT
|
||||||
|
IN THE SAME FILE REMAIN UNDER COPYRIGHT OF THE ORIGINAL AUTHOR, BOTH
|
||||||
|
SOURCE AND OBJECT CODE ARE MADE FREELY AVAILABLE WITHOUT CHARGE, AND
|
||||||
|
CLEAR NOTICE IS GIVEN OF THE MODIFICATIONS. Distribution of this code as
|
||||||
|
part of a commercial system is permissible ONLY BY DIRECT ARRANGEMENT
|
||||||
|
WITH THE AUTHOR. (If you are not directly supplying this code to a
|
||||||
|
customer, and you are instead telling them how they can obtain it for
|
||||||
|
free, then you are not required to make any arrangement with me.)
|
||||||
|
|
||||||
|
------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
The files included in this distribution are:
|
||||||
|
|
||||||
|
README The file you're reading now.
|
||||||
|
triangle.c Complete C source code for Triangle.
|
||||||
|
showme.c Complete C source code for Show Me.
|
||||||
|
triangle.h Include file for calling Triangle from another program.
|
||||||
|
tricall.c Sample program that calls Triangle.
|
||||||
|
makefile Makefile for compiling Triangle and Show Me.
|
||||||
|
A.poly A sample input file.
|
||||||
|
|
||||||
|
Each of Triangle and Show Me is a single portable C file. The easiest way
|
||||||
|
to compile them is to edit and use the included makefile. Before
|
||||||
|
compiling, read the makefile, which describes your options, and edit it
|
||||||
|
accordingly. You should specify:
|
||||||
|
|
||||||
|
The source and binary directories.
|
||||||
|
|
||||||
|
The C compiler and level of optimization.
|
||||||
|
|
||||||
|
The "correct" directories for include files (especially X include files),
|
||||||
|
if necessary.
|
||||||
|
|
||||||
|
Do you want single precision or double? (The default is double.) Do you
|
||||||
|
want to leave out some of Triangle's features to reduce the size of the
|
||||||
|
executable file? Investigate the SINGLE, REDUCED, and CDT_ONLY symbols.
|
||||||
|
|
||||||
|
If yours is not a Unix system, define the NO_TIMER symbol to remove the
|
||||||
|
Unix-specific timing code. Also, don't try to compile Show Me; it only
|
||||||
|
works with X Windows.
|
||||||
|
|
||||||
|
If you are compiling on an Intel x86 CPU and using gcc w/Linux or
|
||||||
|
Microsoft C, be sure to define the LINUX or CPU86 (for Microsoft) symbol
|
||||||
|
during compilation so that the exact arithmetic works right.
|
||||||
|
|
||||||
|
Once you've done this, type "make" to compile the programs. Alternatively,
|
||||||
|
the files are usually easy to compile without a makefile:
|
||||||
|
|
||||||
|
cc -O -o triangle triangle.c -lm
|
||||||
|
cc -O -o showme showme.c -lX11
|
||||||
|
|
||||||
|
On some systems, the C compiler won't be able to find the X include files
|
||||||
|
or libraries, and you'll need to specify an include path or library path:
|
||||||
|
|
||||||
|
cc -O -I/usr/local/include -o showme showme.c -L/usr/local/lib -lX11
|
||||||
|
|
||||||
|
Some processors, including Intel x86 family and possibly Motorola 68xxx
|
||||||
|
family chips, are IEEE conformant but have extended length internal
|
||||||
|
floating-point registers that may defeat Triangle's exact arithmetic
|
||||||
|
routines by failing to cause enough roundoff error! Typically, there is a
|
||||||
|
way to set these internal registers so that they are rounded off to IEEE
|
||||||
|
single or double precision format. I believe (but I'm not certain) that
|
||||||
|
Triangle has the right incantations for x86 chips, if you have gcc running
|
||||||
|
under Linux (define the LINUX compiler symbol) or Microsoft C (define the
|
||||||
|
CPU86 compiler symbol).
|
||||||
|
|
||||||
|
If you have a different processor or operating system, or if I got the
|
||||||
|
incantations wrong, you should check your C compiler or system manuals to
|
||||||
|
find out how to configure these internal registers to the precision you are
|
||||||
|
using. Otherwise, the exact arithmetic routines won't be exact at all.
|
||||||
|
See http://www.cs.cmu.edu/~quake/robust.pc.html for details. Triangle's
|
||||||
|
exact arithmetic hasn't a hope of working on machines like the Cray C90 or
|
||||||
|
Y-MP, which are not IEEE conformant and have inaccurate rounding.
|
||||||
|
|
||||||
|
Triangle and Show Me have both text and HTML documentation. The latter is
|
||||||
|
illustrated. Find it on the Web at
|
||||||
|
|
||||||
|
http://www.cs.cmu.edu/~quake/triangle.html
|
||||||
|
http://www.cs.cmu.edu/~quake/showme.html
|
||||||
|
|
||||||
|
Complete text instructions are printed by invoking each program with the
|
||||||
|
`-h' switch:
|
||||||
|
|
||||||
|
triangle -h
|
||||||
|
showme -h
|
||||||
|
|
||||||
|
The instructions are long; you'll probably want to pipe the output to
|
||||||
|
`more' or `lpr' or redirect it to a file.
|
||||||
|
|
||||||
|
Both programs give a short list of command line options if they are invoked
|
||||||
|
without arguments (that is, just type `triangle' or `showme').
|
||||||
|
|
||||||
|
Try out Triangle on the enclosed sample file, A.poly:
|
||||||
|
|
||||||
|
triangle -p A
|
||||||
|
showme A.poly &
|
||||||
|
|
||||||
|
Triangle will read the Planar Straight Line Graph defined by A.poly, and
|
||||||
|
write its constrained Delaunay triangulation to A.1.node and A.1.ele.
|
||||||
|
Show Me will display the figure defined by A.poly. There are two buttons
|
||||||
|
marked "ele" in the Show Me window; click on the top one. This will cause
|
||||||
|
Show Me to load and display the triangulation.
|
||||||
|
|
||||||
|
For contrast, try running
|
||||||
|
|
||||||
|
triangle -pq A
|
||||||
|
|
||||||
|
Now, click on the same "ele" button. A new triangulation will be loaded;
|
||||||
|
this one having no angles smaller than 20 degrees.
|
||||||
|
|
||||||
|
To see a Voronoi diagram, try this:
|
||||||
|
|
||||||
|
cp A.poly A.node
|
||||||
|
triangle -v A
|
||||||
|
|
||||||
|
Click the "ele" button again. You will see the Delaunay triangulation of
|
||||||
|
the points in A.poly, without the segments. Now click the top "voro" button.
|
||||||
|
You will see the Voronoi diagram corresponding to that Delaunay triangulation.
|
||||||
|
Click the "Reset" button to see the full extent of the diagram.
|
||||||
|
|
||||||
|
------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
If you wish to call Triangle from another program, instructions for doing
|
||||||
|
so are contained in the file `triangle.h' (but read Triangle's regular
|
||||||
|
instructions first!). Also look at `tricall.c', which provides an example
|
||||||
|
of how to call Triangle.
|
||||||
|
|
||||||
|
Type "make trilibrary" to create triangle.o, a callable object file.
|
||||||
|
Alternatively, the object file is usually easy to compile without a
|
||||||
|
makefile:
|
||||||
|
|
||||||
|
cc -DTRILIBRARY -O -c triangle.c
|
||||||
|
|
||||||
|
Type "make distclean" to remove all the object and executable files created
|
||||||
|
by make.
|
||||||
|
|
||||||
|
------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
If you use Triangle, and especially if you use it to accomplish real work,
|
||||||
|
I would like very much to hear from you. A short letter or email (to
|
||||||
|
jrs@cs.berkeley.edu) describing how you use Triangle will mean a lot to me.
|
||||||
|
The more people I know are using this program, the more easily I can
|
||||||
|
justify spending time on improvements and on the three-dimensional
|
||||||
|
successor to Triangle, which in turn will benefit you. Also, I can put you
|
||||||
|
on a list to receive email whenever a new version of Triangle is available.
|
||||||
|
|
||||||
|
If you use a mesh generated by Triangle or plotted by Show Me in a
|
||||||
|
publication, please include an acknowledgment as well. And please spell
|
||||||
|
Triangle with a capital `T'! If you want to include a citation, use
|
||||||
|
`Jonathan Richard Shewchuk, ``Triangle: Engineering a 2D Quality Mesh
|
||||||
|
Generator and Delaunay Triangulator,'' in Applied Computational Geometry:
|
||||||
|
Towards Geometric Engineering (Ming C. Lin and Dinesh Manocha, editors),
|
||||||
|
volume 1148 of Lecture Notes in Computer Science, pages 203-222,
|
||||||
|
Springer-Verlag, Berlin, May 1996. (From the First ACM Workshop on Applied
|
||||||
|
Computational Geometry.)'
|
||||||
|
|
||||||
|
|
||||||
|
Jonathan Richard Shewchuk
|
||||||
|
July 27, 2005
|
292
lib/triangle/include/triangle.h
Normal file
292
lib/triangle/include/triangle.h
Normal file
|
@ -0,0 +1,292 @@
|
||||||
|
/*****************************************************************************/
|
||||||
|
/* */
|
||||||
|
/* (triangle.h) */
|
||||||
|
/* */
|
||||||
|
/* Include file for programs that call Triangle. */
|
||||||
|
/* */
|
||||||
|
/* Accompanies Triangle Version 1.6 */
|
||||||
|
/* July 28, 2005 */
|
||||||
|
/* */
|
||||||
|
/* Copyright 1996, 2005 */
|
||||||
|
/* Jonathan Richard Shewchuk */
|
||||||
|
/* 2360 Woolsey #H */
|
||||||
|
/* Berkeley, California 94705-1927 */
|
||||||
|
/* jrs@cs.berkeley.edu */
|
||||||
|
/* */
|
||||||
|
/*****************************************************************************/
|
||||||
|
|
||||||
|
/*****************************************************************************/
|
||||||
|
/* */
|
||||||
|
/* How to call Triangle from another program */
|
||||||
|
/* */
|
||||||
|
/* */
|
||||||
|
/* If you haven't read Triangle's instructions (run "triangle -h" to read */
|
||||||
|
/* them), you won't understand what follows. */
|
||||||
|
/* */
|
||||||
|
/* Triangle must be compiled into an object file (triangle.o) with the */
|
||||||
|
/* TRILIBRARY symbol defined (generally by using the -DTRILIBRARY compiler */
|
||||||
|
/* switch). The makefile included with Triangle will do this for you if */
|
||||||
|
/* you run "make trilibrary". The resulting object file can be called via */
|
||||||
|
/* the procedure triangulate(). */
|
||||||
|
/* */
|
||||||
|
/* If the size of the object file is important to you, you may wish to */
|
||||||
|
/* generate a reduced version of triangle.o. The REDUCED symbol gets rid */
|
||||||
|
/* of all features that are primarily of research interest. Specifically, */
|
||||||
|
/* the -DREDUCED switch eliminates Triangle's -i, -F, -s, and -C switches. */
|
||||||
|
/* The CDT_ONLY symbol gets rid of all meshing algorithms above and beyond */
|
||||||
|
/* constrained Delaunay triangulation. Specifically, the -DCDT_ONLY switch */
|
||||||
|
/* eliminates Triangle's -r, -q, -a, -u, -D, -Y, -S, and -s switches. */
|
||||||
|
/* */
|
||||||
|
/* IMPORTANT: These definitions (TRILIBRARY, REDUCED, CDT_ONLY) must be */
|
||||||
|
/* made in the makefile or in triangle.c itself. Putting these definitions */
|
||||||
|
/* in this file (triangle.h) will not create the desired effect. */
|
||||||
|
/* */
|
||||||
|
/* */
|
||||||
|
/* The calling convention for triangulate() follows. */
|
||||||
|
/* */
|
||||||
|
/* void triangulate(triswitches, in, out, vorout) */
|
||||||
|
/* char *triswitches; */
|
||||||
|
/* struct triangulateio *in; */
|
||||||
|
/* struct triangulateio *out; */
|
||||||
|
/* struct triangulateio *vorout; */
|
||||||
|
/* */
|
||||||
|
/* `triswitches' is a string containing the command line switches you wish */
|
||||||
|
/* to invoke. No initial dash is required. Some suggestions: */
|
||||||
|
/* */
|
||||||
|
/* - You'll probably find it convenient to use the `z' switch so that */
|
||||||
|
/* points (and other items) are numbered from zero. This simplifies */
|
||||||
|
/* indexing, because the first item of any type always starts at index */
|
||||||
|
/* [0] of the corresponding array, whether that item's number is zero or */
|
||||||
|
/* one. */
|
||||||
|
/* - You'll probably want to use the `Q' (quiet) switch in your final code, */
|
||||||
|
/* but you can take advantage of Triangle's printed output (including the */
|
||||||
|
/* `V' switch) while debugging. */
|
||||||
|
/* - If you are not using the `q', `a', `u', `D', `j', or `s' switches, */
|
||||||
|
/* then the output points will be identical to the input points, except */
|
||||||
|
/* possibly for the boundary markers. If you don't need the boundary */
|
||||||
|
/* markers, you should use the `N' (no nodes output) switch to save */
|
||||||
|
/* memory. (If you do need boundary markers, but need to save memory, a */
|
||||||
|
/* good nasty trick is to set out->pointlist equal to in->pointlist */
|
||||||
|
/* before calling triangulate(), so that Triangle overwrites the input */
|
||||||
|
/* points with identical copies.) */
|
||||||
|
/* - The `I' (no iteration numbers) and `g' (.off file output) switches */
|
||||||
|
/* have no effect when Triangle is compiled with TRILIBRARY defined. */
|
||||||
|
/* */
|
||||||
|
/* `in', `out', and `vorout' are descriptions of the input, the output, */
|
||||||
|
/* and the Voronoi output. If the `v' (Voronoi output) switch is not used, */
|
||||||
|
/* `vorout' may be NULL. `in' and `out' may never be NULL. */
|
||||||
|
/* */
|
||||||
|
/* Certain fields of the input and output structures must be initialized, */
|
||||||
|
/* as described below. */
|
||||||
|
/* */
|
||||||
|
/*****************************************************************************/
|
||||||
|
|
||||||
|
/*****************************************************************************/
|
||||||
|
/* */
|
||||||
|
/* The `triangulateio' structure. */
|
||||||
|
/* */
|
||||||
|
/* Used to pass data into and out of the triangulate() procedure. */
|
||||||
|
/* */
|
||||||
|
/* */
|
||||||
|
/* Arrays are used to store points, triangles, markers, and so forth. In */
|
||||||
|
/* all cases, the first item in any array is stored starting at index [0]. */
|
||||||
|
/* However, that item is item number `1' unless the `z' switch is used, in */
|
||||||
|
/* which case it is item number `0'. Hence, you may find it easier to */
|
||||||
|
/* index points (and triangles in the neighbor list) if you use the `z' */
|
||||||
|
/* switch. Unless, of course, you're calling Triangle from a Fortran */
|
||||||
|
/* program. */
|
||||||
|
/* */
|
||||||
|
/* Description of fields (except the `numberof' fields, which are obvious): */
|
||||||
|
/* */
|
||||||
|
/* `pointlist': An array of point coordinates. The first point's x */
|
||||||
|
/* coordinate is at index [0] and its y coordinate at index [1], followed */
|
||||||
|
/* by the coordinates of the remaining points. Each point occupies two */
|
||||||
|
/* REALs. */
|
||||||
|
/* `pointattributelist': An array of point attributes. Each point's */
|
||||||
|
/* attributes occupy `numberofpointattributes' REALs. */
|
||||||
|
/* `pointmarkerlist': An array of point markers; one int per point. */
|
||||||
|
/* */
|
||||||
|
/* `trianglelist': An array of triangle corners. The first triangle's */
|
||||||
|
/* first corner is at index [0], followed by its other two corners in */
|
||||||
|
/* counterclockwise order, followed by any other nodes if the triangle */
|
||||||
|
/* represents a nonlinear element. Each triangle occupies */
|
||||||
|
/* `numberofcorners' ints. */
|
||||||
|
/* `triangleattributelist': An array of triangle attributes. Each */
|
||||||
|
/* triangle's attributes occupy `numberoftriangleattributes' REALs. */
|
||||||
|
/* `trianglearealist': An array of triangle area constraints; one REAL per */
|
||||||
|
/* triangle. Input only. */
|
||||||
|
/* `neighborlist': An array of triangle neighbors; three ints per */
|
||||||
|
/* triangle. Output only. */
|
||||||
|
/* */
|
||||||
|
/* `segmentlist': An array of segment endpoints. The first segment's */
|
||||||
|
/* endpoints are at indices [0] and [1], followed by the remaining */
|
||||||
|
/* segments. Two ints per segment. */
|
||||||
|
/* `segmentmarkerlist': An array of segment markers; one int per segment. */
|
||||||
|
/* */
|
||||||
|
/* `holelist': An array of holes. The first hole's x and y coordinates */
|
||||||
|
/* are at indices [0] and [1], followed by the remaining holes. Two */
|
||||||
|
/* REALs per hole. Input only, although the pointer is copied to the */
|
||||||
|
/* output structure for your convenience. */
|
||||||
|
/* */
|
||||||
|
/* `regionlist': An array of regional attributes and area constraints. */
|
||||||
|
/* The first constraint's x and y coordinates are at indices [0] and [1], */
|
||||||
|
/* followed by the regional attribute at index [2], followed by the */
|
||||||
|
/* maximum area at index [3], followed by the remaining area constraints. */
|
||||||
|
/* Four REALs per area constraint. Note that each regional attribute is */
|
||||||
|
/* used only if you select the `A' switch, and each area constraint is */
|
||||||
|
/* used only if you select the `a' switch (with no number following), but */
|
||||||
|
/* omitting one of these switches does not change the memory layout. */
|
||||||
|
/* Input only, although the pointer is copied to the output structure for */
|
||||||
|
/* your convenience. */
|
||||||
|
/* */
|
||||||
|
/* `edgelist': An array of edge endpoints. The first edge's endpoints are */
|
||||||
|
/* at indices [0] and [1], followed by the remaining edges. Two ints per */
|
||||||
|
/* edge. Output only. */
|
||||||
|
/* `edgemarkerlist': An array of edge markers; one int per edge. Output */
|
||||||
|
/* only. */
|
||||||
|
/* `normlist': An array of normal vectors, used for infinite rays in */
|
||||||
|
/* Voronoi diagrams. The first normal vector's x and y magnitudes are */
|
||||||
|
/* at indices [0] and [1], followed by the remaining vectors. For each */
|
||||||
|
/* finite edge in a Voronoi diagram, the normal vector written is the */
|
||||||
|
/* zero vector. Two REALs per edge. Output only. */
|
||||||
|
/* */
|
||||||
|
/* */
|
||||||
|
/* Any input fields that Triangle will examine must be initialized. */
|
||||||
|
/* Furthermore, for each output array that Triangle will write to, you */
|
||||||
|
/* must either provide space by setting the appropriate pointer to point */
|
||||||
|
/* to the space you want the data written to, or you must initialize the */
|
||||||
|
/* pointer to NULL, which tells Triangle to allocate space for the results. */
|
||||||
|
/* The latter option is preferable, because Triangle always knows exactly */
|
||||||
|
/* how much space to allocate. The former option is provided mainly for */
|
||||||
|
/* people who need to call Triangle from Fortran code, though it also makes */
|
||||||
|
/* possible some nasty space-saving tricks, like writing the output to the */
|
||||||
|
/* same arrays as the input. */
|
||||||
|
/* */
|
||||||
|
/* Triangle will not free() any input or output arrays, including those it */
|
||||||
|
/* allocates itself; that's up to you. You should free arrays allocated by */
|
||||||
|
/* Triangle by calling the trifree() procedure defined below. (By default, */
|
||||||
|
/* trifree() just calls the standard free() library procedure, but */
|
||||||
|
/* applications that call triangulate() may replace trimalloc() and */
|
||||||
|
/* trifree() in triangle.c to use specialized memory allocators.) */
|
||||||
|
/* */
|
||||||
|
/* Here's a guide to help you decide which fields you must initialize */
|
||||||
|
/* before you call triangulate(). */
|
||||||
|
/* */
|
||||||
|
/* `in': */
|
||||||
|
/* */
|
||||||
|
/* - `pointlist' must always point to a list of points; `numberofpoints' */
|
||||||
|
/* and `numberofpointattributes' must be properly set. */
|
||||||
|
/* `pointmarkerlist' must either be set to NULL (in which case all */
|
||||||
|
/* markers default to zero), or must point to a list of markers. If */
|
||||||
|
/* `numberofpointattributes' is not zero, `pointattributelist' must */
|
||||||
|
/* point to a list of point attributes. */
|
||||||
|
/* - If the `r' switch is used, `trianglelist' must point to a list of */
|
||||||
|
/* triangles, and `numberoftriangles', `numberofcorners', and */
|
||||||
|
/* `numberoftriangleattributes' must be properly set. If */
|
||||||
|
/* `numberoftriangleattributes' is not zero, `triangleattributelist' */
|
||||||
|
/* must point to a list of triangle attributes. If the `a' switch is */
|
||||||
|
/* used (with no number following), `trianglearealist' must point to a */
|
||||||
|
/* list of triangle area constraints. `neighborlist' may be ignored. */
|
||||||
|
/* - If the `p' switch is used, `segmentlist' must point to a list of */
|
||||||
|
/* segments, `numberofsegments' must be properly set, and */
|
||||||
|
/* `segmentmarkerlist' must either be set to NULL (in which case all */
|
||||||
|
/* markers default to zero), or must point to a list of markers. */
|
||||||
|
/* - If the `p' switch is used without the `r' switch, then */
|
||||||
|
/* `numberofholes' and `numberofregions' must be properly set. If */
|
||||||
|
/* `numberofholes' is not zero, `holelist' must point to a list of */
|
||||||
|
/* holes. If `numberofregions' is not zero, `regionlist' must point to */
|
||||||
|
/* a list of region constraints. */
|
||||||
|
/* - If the `p' switch is used, `holelist', `numberofholes', */
|
||||||
|
/* `regionlist', and `numberofregions' is copied to `out'. (You can */
|
||||||
|
/* nonetheless get away with not initializing them if the `r' switch is */
|
||||||
|
/* used.) */
|
||||||
|
/* - `edgelist', `edgemarkerlist', `normlist', and `numberofedges' may be */
|
||||||
|
/* ignored. */
|
||||||
|
/* */
|
||||||
|
/* `out': */
|
||||||
|
/* */
|
||||||
|
/* - `pointlist' must be initialized (NULL or pointing to memory) unless */
|
||||||
|
/* the `N' switch is used. `pointmarkerlist' must be initialized */
|
||||||
|
/* unless the `N' or `B' switch is used. If `N' is not used and */
|
||||||
|
/* `in->numberofpointattributes' is not zero, `pointattributelist' must */
|
||||||
|
/* be initialized. */
|
||||||
|
/* - `trianglelist' must be initialized unless the `E' switch is used. */
|
||||||
|
/* `neighborlist' must be initialized if the `n' switch is used. If */
|
||||||
|
/* the `E' switch is not used and (`in->numberofelementattributes' is */
|
||||||
|
/* not zero or the `A' switch is used), `elementattributelist' must be */
|
||||||
|
/* initialized. `trianglearealist' may be ignored. */
|
||||||
|
/* - `segmentlist' must be initialized if the `p' or `c' switch is used, */
|
||||||
|
/* and the `P' switch is not used. `segmentmarkerlist' must also be */
|
||||||
|
/* initialized under these circumstances unless the `B' switch is used. */
|
||||||
|
/* - `edgelist' must be initialized if the `e' switch is used. */
|
||||||
|
/* `edgemarkerlist' must be initialized if the `e' switch is used and */
|
||||||
|
/* the `B' switch is not. */
|
||||||
|
/* - `holelist', `regionlist', `normlist', and all scalars may be ignored.*/
|
||||||
|
/* */
|
||||||
|
/* `vorout' (only needed if `v' switch is used): */
|
||||||
|
/* */
|
||||||
|
/* - `pointlist' must be initialized. If `in->numberofpointattributes' */
|
||||||
|
/* is not zero, `pointattributelist' must be initialized. */
|
||||||
|
/* `pointmarkerlist' may be ignored. */
|
||||||
|
/* - `edgelist' and `normlist' must both be initialized. */
|
||||||
|
/* `edgemarkerlist' may be ignored. */
|
||||||
|
/* - Everything else may be ignored. */
|
||||||
|
/* */
|
||||||
|
/* After a call to triangulate(), the valid fields of `out' and `vorout' */
|
||||||
|
/* will depend, in an obvious way, on the choice of switches used. Note */
|
||||||
|
/* that when the `p' switch is used, the pointers `holelist' and */
|
||||||
|
/* `regionlist' are copied from `in' to `out', but no new space is */
|
||||||
|
/* allocated; be careful that you don't free() the same array twice. On */
|
||||||
|
/* the other hand, Triangle will never copy the `pointlist' pointer (or any */
|
||||||
|
/* others); new space is allocated for `out->pointlist', or if the `N' */
|
||||||
|
/* switch is used, `out->pointlist' remains uninitialized. */
|
||||||
|
/* */
|
||||||
|
/* All of the meaningful `numberof' fields will be properly set; for */
|
||||||
|
/* instance, `numberofedges' will represent the number of edges in the */
|
||||||
|
/* triangulation whether or not the edges were written. If segments are */
|
||||||
|
/* not used, `numberofsegments' will indicate the number of boundary edges. */
|
||||||
|
/* */
|
||||||
|
/*****************************************************************************/
|
||||||
|
|
||||||
|
#define REAL double
|
||||||
|
#define VOID int
|
||||||
|
|
||||||
|
struct triangulateio {
|
||||||
|
REAL *pointlist; /* In / out */
|
||||||
|
REAL *pointattributelist; /* In / out */
|
||||||
|
int *pointmarkerlist; /* In / out */
|
||||||
|
int numberofpoints; /* In / out */
|
||||||
|
int numberofpointattributes; /* In / out */
|
||||||
|
|
||||||
|
int *trianglelist; /* In / out */
|
||||||
|
REAL *triangleattributelist; /* In / out */
|
||||||
|
REAL *trianglearealist; /* In only */
|
||||||
|
int *neighborlist; /* Out only */
|
||||||
|
int numberoftriangles; /* In / out */
|
||||||
|
int numberofcorners; /* In / out */
|
||||||
|
int numberoftriangleattributes; /* In / out */
|
||||||
|
|
||||||
|
int *segmentlist; /* In / out */
|
||||||
|
int *segmentmarkerlist; /* In / out */
|
||||||
|
int numberofsegments; /* In / out */
|
||||||
|
|
||||||
|
REAL *holelist; /* In / pointer to array copied out */
|
||||||
|
int numberofholes; /* In / copied out */
|
||||||
|
|
||||||
|
REAL *regionlist; /* In / pointer to array copied out */
|
||||||
|
int numberofregions; /* In / copied out */
|
||||||
|
|
||||||
|
int *edgelist; /* Out only */
|
||||||
|
int *edgemarkerlist; /* Not used with Voronoi diagram; out only */
|
||||||
|
REAL *normlist; /* Used only with Voronoi diagram; out only */
|
||||||
|
int numberofedges; /* Out only */
|
||||||
|
};
|
||||||
|
|
||||||
|
#ifdef ANSI_DECLARATORS
|
||||||
|
void triangulate(char *, struct triangulateio *, struct triangulateio *,
|
||||||
|
struct triangulateio *);
|
||||||
|
void trifree(VOID *memptr);
|
||||||
|
#else /* not ANSI_DECLARATORS */
|
||||||
|
void triangulate();
|
||||||
|
void trifree();
|
||||||
|
#endif /* not ANSI_DECLARATORS */
|
16006
lib/triangle/src/triangle.c
Normal file
16006
lib/triangle/src/triangle.c
Normal file
File diff suppressed because it is too large
Load diff
73478
res/jp.osm
Normal file
73478
res/jp.osm
Normal file
File diff suppressed because it is too large
Load diff
874319
res/leipzig.osm
Normal file
874319
res/leipzig.osm
Normal file
File diff suppressed because it is too large
Load diff
154
src/main.cpp
154
src/main.cpp
|
@ -1,51 +1,135 @@
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
#include <string>
|
||||||
|
#include <algorithm>
|
||||||
|
|
||||||
#include <osmp.hpp>
|
#include <osmp.hpp>
|
||||||
#include <SDL.h>
|
#include <SDL.h>
|
||||||
|
#include <SDL2_gfxPrimitives.h>
|
||||||
|
#include <../include/multipolygon.hpp>
|
||||||
|
|
||||||
// Map values from one interval [A, B] to another [a, b]
|
// Map values from one interval [A, B] to another [a, b]
|
||||||
inline float Map(float A, float B, float a, float b, float x);
|
inline float Map(float A, float B, float a, float b, float x);
|
||||||
|
|
||||||
// A structure to hold a sequence of 2D points
|
typedef struct sArea
|
||||||
typedef struct sRenderableWay
|
|
||||||
{
|
{
|
||||||
size_t length;
|
size_t length;
|
||||||
|
Uint8 r = 0;
|
||||||
|
Uint8 g = 0;
|
||||||
|
Uint8 b = 10;
|
||||||
|
Sint16* x;
|
||||||
|
Sint16* y;
|
||||||
|
} Area;
|
||||||
|
|
||||||
|
typedef struct sHighway
|
||||||
|
{
|
||||||
|
size_t length;
|
||||||
|
Uint8 r, g, b;
|
||||||
SDL_FPoint* points;
|
SDL_FPoint* points;
|
||||||
} RenderableWay;
|
} Highway;
|
||||||
|
|
||||||
int main(int argc, char** argv)
|
int main(int argc, char** argv)
|
||||||
{
|
{
|
||||||
// Load map data and calculate window size
|
// Load map data and calculate window size
|
||||||
osmp::Object* obj = new osmp::Object("bigmap.osm");
|
osmp::Object* obj = new osmp::Object("leipzig.osm");
|
||||||
osmp::Bounds bounds = obj->bounds;
|
osmp::Bounds bounds = obj->bounds;
|
||||||
float aspectRatio = (float)(bounds.maxlon - bounds.minlon) / (float)(bounds.maxlat - bounds.minlat);
|
float aspectRatio = (float)(bounds.maxlon - bounds.minlon) / (float)(bounds.maxlat - bounds.minlat);
|
||||||
int windowWidth = 800;
|
int windowWidth = 2000;
|
||||||
int windowHeight = windowWidth / aspectRatio;
|
int windowHeight = windowWidth / aspectRatio;
|
||||||
|
|
||||||
// Fetch all the ways
|
// Fetch all the ways
|
||||||
std::vector<osmp::Way*> ways = obj->GetWays();
|
std::vector<std::shared_ptr<osmp::Way>> ways = obj->GetWays();
|
||||||
|
|
||||||
// Turn them into renderable ways by mapping the global coordinates to screen coordinates (do this smarter in the future pls)
|
// Turn them into renderable ways by mapping the global coordinates to screen coordinates (do this smarter in the future pls)
|
||||||
std::vector<RenderableWay> rWays;
|
std::vector<Area> buildings;
|
||||||
for (osmp::Way* way : ways)
|
std::vector<Highway> highways;
|
||||||
|
for (std::shared_ptr<osmp::Way> way : ways)
|
||||||
{
|
{
|
||||||
std::vector<const osmp::Node*> nodes = way->GetNodes();
|
const std::vector<std::shared_ptr<osmp::Node>>& nodes = way->GetNodes();
|
||||||
|
std::string highwayVal = way->GetTag("highway");
|
||||||
RenderableWay rWay;
|
std::string railwayVal = way->GetTag("railway");
|
||||||
rWay.length = nodes.size();
|
if (way->area)
|
||||||
rWay.points = new SDL_FPoint[rWay.length];
|
|
||||||
|
|
||||||
for (int i = 0; i < rWay.length; i++)
|
|
||||||
{
|
{
|
||||||
rWay.points[i].x = Map(bounds.minlon, bounds.maxlon, 0, windowWidth, nodes[i]->lon);
|
if (way->GetTag("building") == "")
|
||||||
rWay.points[i].y = 1000 - Map(bounds.minlat, bounds.maxlat, 0, windowHeight, nodes[i]->lat);
|
{
|
||||||
}
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
rWays.push_back(rWay);
|
Area area;
|
||||||
|
area.length = nodes.size();
|
||||||
|
area.x = new Sint16[area.length];
|
||||||
|
area.y = new Sint16[area.length];
|
||||||
|
|
||||||
|
area.r = 150;
|
||||||
|
area.g = 150;
|
||||||
|
area.b = 150;
|
||||||
|
|
||||||
|
for (int i = 0; i < area.length; i++)
|
||||||
|
{
|
||||||
|
area.x[i] = Map(bounds.minlon, bounds.maxlon, 0, windowWidth, nodes[i]->lon);
|
||||||
|
area.y[i] = windowHeight - Map(bounds.minlat, bounds.maxlat, 0, windowHeight, nodes[i]->lat);
|
||||||
|
}
|
||||||
|
|
||||||
|
buildings.push_back(area);
|
||||||
|
}
|
||||||
|
else if (highwayVal != "")
|
||||||
|
{
|
||||||
|
Highway highway;
|
||||||
|
highway.length = nodes.size();
|
||||||
|
highway.points = new SDL_FPoint[highway.length];
|
||||||
|
|
||||||
|
for (int i = 0; i < highway.length; i++)
|
||||||
|
{
|
||||||
|
highway.points[i].x = Map(bounds.minlon, bounds.maxlon, 0, windowWidth, nodes[i]->lon);
|
||||||
|
highway.points[i].y = windowHeight - Map(bounds.minlat, bounds.maxlat, 0, windowHeight, nodes[i]->lat);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (highwayVal == "motorway") { highway.r = 226; highway.g = 122; highway.b = 143; }
|
||||||
|
else if (highwayVal == "trunk") { highway.r = 249; highway.g = 178; highway.b = 156; }
|
||||||
|
else if (highwayVal == "primary") { highway.r = 252; highway.g = 206; highway.b = 144; }
|
||||||
|
else if (highwayVal == "secondary") { highway.r = 244; highway.g = 251; highway.b = 173; }
|
||||||
|
else if (highwayVal == "tertiary") { highway.r = 244; highway.g = 244; highway.b = 250; }
|
||||||
|
else if (highwayVal == "footway") { highway.r = 233; highway.g = 140; highway.b = 124; }
|
||||||
|
else { highway.r = 15; highway.g = 15; highway.b = 20; }
|
||||||
|
|
||||||
|
highways.push_back(highway);
|
||||||
|
}
|
||||||
|
else if (railwayVal != "")
|
||||||
|
{
|
||||||
|
Highway railway;
|
||||||
|
railway.length = nodes.size();
|
||||||
|
railway.points = new SDL_FPoint[railway.length];
|
||||||
|
|
||||||
|
for (int i = 0; i < railway.length; i++)
|
||||||
|
{
|
||||||
|
railway.points[i].x = Map(bounds.minlon, bounds.maxlon, 0, windowWidth, nodes[i]->lon);
|
||||||
|
railway.points[i].y = windowHeight - Map(bounds.minlat, bounds.maxlat, 0, windowHeight, nodes[i]->lat);
|
||||||
|
}
|
||||||
|
|
||||||
|
railway.r = 80; railway.g = 80; railway.b = 80;
|
||||||
|
|
||||||
|
highways.push_back(railway);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Fetch all relations
|
||||||
|
std::vector<std::shared_ptr<osmp::Relation>> relations = obj->GetRelations();
|
||||||
|
std::vector<Multipolygon> multipolygons;
|
||||||
|
for (const std::shared_ptr<osmp::Relation>& relation : relations)
|
||||||
|
{
|
||||||
|
if (relation->GetRelationType() == "multipolygon" && !relation->HasNullMembers())
|
||||||
|
{
|
||||||
|
Multipolygon mp = Multipolygon(relation, windowWidth, windowHeight, obj->bounds);
|
||||||
|
multipolygons.push_back(mp);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
std::sort(multipolygons.begin(), multipolygons.end());
|
||||||
|
|
||||||
|
|
||||||
// Release map data
|
// Release map data
|
||||||
|
relations.clear();
|
||||||
|
ways.clear();
|
||||||
delete obj;
|
delete obj;
|
||||||
|
|
||||||
// Initiaize graphics API
|
// Initiaize graphics API
|
||||||
|
@ -84,16 +168,25 @@ int main(int argc, char** argv)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
SDL_SetRenderDrawColor(renderer, 0, 0, 0, 255);
|
SDL_SetRenderDrawColor(renderer, 240, 240, 250, 255);
|
||||||
SDL_RenderClear(renderer);
|
SDL_RenderClear(renderer);
|
||||||
|
|
||||||
// Render the ways
|
for (Multipolygon& multipolygon : multipolygons) {
|
||||||
SDL_SetRenderDrawColor(renderer, 255, 255, 255, 255);
|
multipolygon.Draw(renderer);
|
||||||
for (RenderableWay rWay : rWays)
|
|
||||||
{
|
|
||||||
SDL_RenderDrawLinesF(renderer, rWay.points, rWay.length);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for (Area& area : buildings)
|
||||||
|
{
|
||||||
|
filledPolygonRGBA(renderer, area.x, area.y, area.length, area.r, area.g, area.b, 255);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (Highway& highway : highways)
|
||||||
|
{
|
||||||
|
SDL_SetRenderDrawColor(renderer, highway.r, highway.g, highway.b, 255);
|
||||||
|
SDL_RenderDrawLinesF(renderer, highway.points, highway.length);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
SDL_RenderPresent(renderer);
|
SDL_RenderPresent(renderer);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -103,8 +196,13 @@ int main(int argc, char** argv)
|
||||||
|
|
||||||
SDL_Quit();
|
SDL_Quit();
|
||||||
|
|
||||||
for (RenderableWay& rWay : rWays)
|
for (Area& area : buildings) {
|
||||||
delete[] rWay.points;
|
delete[] area.x;
|
||||||
|
delete[] area.y;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (Highway& highway : highways)
|
||||||
|
delete[] highway.points;
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
677
src/multipolygon.cpp
Normal file
677
src/multipolygon.cpp
Normal file
|
@ -0,0 +1,677 @@
|
||||||
|
#include "..\include\multipolygon.hpp"
|
||||||
|
|
||||||
|
#include <vector>
|
||||||
|
#include <iostream>
|
||||||
|
|
||||||
|
#include <triangle.h>
|
||||||
|
#include <osmway.hpp>
|
||||||
|
#include <osmnode.hpp>
|
||||||
|
#include <SDL.h>
|
||||||
|
#include <SDL2_gfxPrimitives.h>
|
||||||
|
|
||||||
|
#define BREAKIF(x) if(relation->id == x) __debugbreak()
|
||||||
|
|
||||||
|
struct TriangulationData {
|
||||||
|
std::vector<REAL> vertices, holes;
|
||||||
|
std::vector<int> segments;
|
||||||
|
};
|
||||||
|
|
||||||
|
// 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;
|
||||||
|
}
|
||||||
|
|
||||||
|
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)
|
||||||
|
{
|
||||||
|
if (relation->HasNullMembers())
|
||||||
|
return;
|
||||||
|
|
||||||
|
std::vector<TriangulationData> data;
|
||||||
|
|
||||||
|
std::vector<osmp::Relation::Member> ways = relation->GetWays();
|
||||||
|
std::vector<std::shared_ptr<osmp::Node>> nodes;
|
||||||
|
int run = 1;
|
||||||
|
|
||||||
|
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")
|
||||||
|
{
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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())
|
||||||
|
{
|
||||||
|
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;
|
||||||
|
for (const std::shared_ptr<osmp::Node>& node : nodes) {
|
||||||
|
vertices.push_back(Map(bounds.minlon, bounds.maxlon, 0, width, node->lon));
|
||||||
|
vertices.push_back(height - Map(bounds.minlat, bounds.maxlat, 0, height, node->lat));
|
||||||
|
}
|
||||||
|
|
||||||
|
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) {
|
||||||
|
td.segments.push_back(segNum);
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// TODO: Make a color map
|
||||||
|
|
||||||
|
std::string tag = "";
|
||||||
|
tag = relation->GetTag("indoor");
|
||||||
|
if (tag != "")
|
||||||
|
{
|
||||||
|
rendering = RenderType::INDOOR;
|
||||||
|
r = 150;
|
||||||
|
g = 150;
|
||||||
|
b = 150;
|
||||||
|
}
|
||||||
|
|
||||||
|
tag = relation->GetTag("building");
|
||||||
|
if (tag != "" || relation->GetTag("building:colour") != "" || relation->GetTag("building:material") != "" || relation->GetTag("building:part") != "")
|
||||||
|
{
|
||||||
|
r = 150;
|
||||||
|
g = 150;
|
||||||
|
b = 150;
|
||||||
|
}
|
||||||
|
|
||||||
|
tag = relation->GetTag("natural");
|
||||||
|
if (tag != "")
|
||||||
|
{
|
||||||
|
if (tag == "wood") {
|
||||||
|
r = 157;
|
||||||
|
g = 202;
|
||||||
|
b = 138;
|
||||||
|
}
|
||||||
|
else if (tag == "scrub") {
|
||||||
|
r = 200;
|
||||||
|
g = 215;
|
||||||
|
b = 171;
|
||||||
|
}
|
||||||
|
else if (tag == "heath") {
|
||||||
|
r = 214;
|
||||||
|
g = 217;
|
||||||
|
b = 159;
|
||||||
|
}
|
||||||
|
else if (tag == "water") {
|
||||||
|
r = 166;
|
||||||
|
g = 198;
|
||||||
|
b = 198;
|
||||||
|
}
|
||||||
|
else if (tag == "grassland") {
|
||||||
|
r = 205;
|
||||||
|
g = 235;
|
||||||
|
b = 176;
|
||||||
|
}
|
||||||
|
else if (tag == "floodplain") {
|
||||||
|
r = 174;
|
||||||
|
g = 236;
|
||||||
|
b = 190;
|
||||||
|
}
|
||||||
|
else if (tag == "sand") {
|
||||||
|
r = 234;
|
||||||
|
g = 222;
|
||||||
|
b = 189;
|
||||||
|
}
|
||||||
|
else if (tag == "scree") {
|
||||||
|
r = 237;
|
||||||
|
g = 228;
|
||||||
|
b = 220;
|
||||||
|
}
|
||||||
|
else if (tag == "bare_rock") {
|
||||||
|
r = 213;
|
||||||
|
g = 209;
|
||||||
|
b = 204;
|
||||||
|
}
|
||||||
|
else if (tag == "tree_row") {
|
||||||
|
r = 169;
|
||||||
|
g = 206;
|
||||||
|
b = 161;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
tag = relation->GetTag("water");
|
||||||
|
if (tag != "")
|
||||||
|
{
|
||||||
|
r = 106;
|
||||||
|
g = 151;
|
||||||
|
b = 255;
|
||||||
|
}
|
||||||
|
|
||||||
|
tag = relation->GetTag("waterway");
|
||||||
|
if (tag != "")
|
||||||
|
{
|
||||||
|
r = 106;
|
||||||
|
g = 151;
|
||||||
|
b = 255;
|
||||||
|
}
|
||||||
|
|
||||||
|
tag = relation->GetTag("landuse");
|
||||||
|
if (tag != "")
|
||||||
|
{
|
||||||
|
if (tag == "grass")
|
||||||
|
{
|
||||||
|
r = 207;
|
||||||
|
g = 237;
|
||||||
|
b = 165;
|
||||||
|
}
|
||||||
|
else if (tag == "commercial")
|
||||||
|
{
|
||||||
|
r = 238;
|
||||||
|
g = 205;
|
||||||
|
b = 205;
|
||||||
|
}
|
||||||
|
else if (tag == "residential")
|
||||||
|
{
|
||||||
|
r = 218;
|
||||||
|
g = 218;
|
||||||
|
b = 218;
|
||||||
|
}
|
||||||
|
else if (tag == "forest")
|
||||||
|
{
|
||||||
|
r = 157;
|
||||||
|
g = 202;
|
||||||
|
b = 138;
|
||||||
|
}
|
||||||
|
else if (tag == "basin")
|
||||||
|
{
|
||||||
|
r = 170;
|
||||||
|
g = 211;
|
||||||
|
b = 223;
|
||||||
|
}
|
||||||
|
else if (tag == "allotments")
|
||||||
|
{
|
||||||
|
r = 201;
|
||||||
|
g = 225;
|
||||||
|
b = 191;
|
||||||
|
}
|
||||||
|
else if (tag == "railway")
|
||||||
|
{
|
||||||
|
r = 230;
|
||||||
|
g = 209;
|
||||||
|
b = 227;
|
||||||
|
}
|
||||||
|
else if (tag == "construction")
|
||||||
|
{
|
||||||
|
r = 199;
|
||||||
|
g = 199;
|
||||||
|
b = 180;
|
||||||
|
}
|
||||||
|
else if (tag == "retail")
|
||||||
|
{
|
||||||
|
r = 254;
|
||||||
|
g = 202;
|
||||||
|
b = 197;
|
||||||
|
}
|
||||||
|
else if (tag == "village_green")
|
||||||
|
{
|
||||||
|
r = 205;
|
||||||
|
g = 235;
|
||||||
|
b = 176;
|
||||||
|
}
|
||||||
|
else if (tag == "meadow")
|
||||||
|
{
|
||||||
|
r = 205;
|
||||||
|
g = 236;
|
||||||
|
b = 176;
|
||||||
|
}
|
||||||
|
else if (tag == "cemetery")
|
||||||
|
{
|
||||||
|
r = 170;
|
||||||
|
g = 203;
|
||||||
|
b = 175;
|
||||||
|
}
|
||||||
|
else if (tag == "brownfield") {
|
||||||
|
r = 167;
|
||||||
|
g = 168;
|
||||||
|
b = 126;
|
||||||
|
}
|
||||||
|
else if (tag == "recreation_ground") {
|
||||||
|
r = 223;
|
||||||
|
g = 252;
|
||||||
|
b = 226;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
tag = relation->GetTag("leisure");
|
||||||
|
if (tag != "")
|
||||||
|
{
|
||||||
|
if (tag == "park")
|
||||||
|
{
|
||||||
|
r = 205;
|
||||||
|
g = 247;
|
||||||
|
b = 201;
|
||||||
|
}
|
||||||
|
else if (tag == "garden")
|
||||||
|
{
|
||||||
|
r = 205;
|
||||||
|
g = 235;
|
||||||
|
b = 176;
|
||||||
|
}
|
||||||
|
else if (tag == "pitch")
|
||||||
|
{
|
||||||
|
r = 170;
|
||||||
|
g = 224;
|
||||||
|
b = 203;
|
||||||
|
}
|
||||||
|
else if (tag == "sports_centre")
|
||||||
|
{
|
||||||
|
r = 223;
|
||||||
|
g = 252;
|
||||||
|
b = 226;
|
||||||
|
}
|
||||||
|
else if (tag == "track")
|
||||||
|
{
|
||||||
|
r = 170;
|
||||||
|
g = 224;
|
||||||
|
b = 203;
|
||||||
|
}
|
||||||
|
else if (tag == "slipway")
|
||||||
|
{
|
||||||
|
r = 0;
|
||||||
|
g = 146;
|
||||||
|
b = 218;
|
||||||
|
}
|
||||||
|
else if (tag == "playground")
|
||||||
|
{
|
||||||
|
r = 223;
|
||||||
|
g = 252;
|
||||||
|
b = 226;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
tag = relation->GetTag("tourism");
|
||||||
|
if (tag != "")
|
||||||
|
{
|
||||||
|
if (tag == "zoo") {
|
||||||
|
rendering = RenderType::OUTLINE;
|
||||||
|
r = 147;
|
||||||
|
g = 84;
|
||||||
|
b = 115;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
tag = relation->GetTag("man_made");
|
||||||
|
if (tag != "")
|
||||||
|
{
|
||||||
|
if (tag == "bridge") {
|
||||||
|
r = 184;
|
||||||
|
g = 184;
|
||||||
|
b = 184;
|
||||||
|
}
|
||||||
|
else if (tag == "wastewater_plant") {
|
||||||
|
r = 230;
|
||||||
|
g = 209;
|
||||||
|
b = 227;
|
||||||
|
}
|
||||||
|
else if (tag == "pier") {
|
||||||
|
r = 250;
|
||||||
|
g = 250;
|
||||||
|
b = 255;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
tag = relation->GetTag("amenity");
|
||||||
|
if (tag != "")
|
||||||
|
{
|
||||||
|
if (tag == "parking" || tag == "bicycle_parking") {
|
||||||
|
r = 100;
|
||||||
|
g = 100;
|
||||||
|
b = 120;
|
||||||
|
}
|
||||||
|
else if (tag == "school" || tag == "university" || tag == "kindergarten") {
|
||||||
|
r = 255;
|
||||||
|
g = 255;
|
||||||
|
b = 229;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
tag = relation->GetTag("place");
|
||||||
|
if (tag != "")
|
||||||
|
{
|
||||||
|
r = 180;
|
||||||
|
g = 180;
|
||||||
|
b = 180;
|
||||||
|
}
|
||||||
|
|
||||||
|
tag = relation->GetTag("public_transport");
|
||||||
|
if (tag != "")
|
||||||
|
{
|
||||||
|
if (tag == "platform")
|
||||||
|
{
|
||||||
|
r = 180;
|
||||||
|
g = 180;
|
||||||
|
b = 190;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
tag = relation->GetTag("highway");
|
||||||
|
if (tag != "")
|
||||||
|
{
|
||||||
|
if (tag == "pedestrian")
|
||||||
|
{
|
||||||
|
r = 213;
|
||||||
|
g = 212;
|
||||||
|
b = 227;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
tag = relation->GetTag("area:highway");
|
||||||
|
if (tag != "")
|
||||||
|
{
|
||||||
|
if (tag == "primary")
|
||||||
|
{
|
||||||
|
r = 255;
|
||||||
|
g = 255;
|
||||||
|
b = 229;
|
||||||
|
}
|
||||||
|
else if (tag == "secondary")
|
||||||
|
{
|
||||||
|
r = 244;
|
||||||
|
g = 251;
|
||||||
|
b = 173;
|
||||||
|
}
|
||||||
|
else if (tag == "footway" || tag == "cycleway" || tag == "footway;cycleway") // TODO: Apparently you can list values??? check with the standard.
|
||||||
|
{
|
||||||
|
r = 233;
|
||||||
|
g = 140;
|
||||||
|
b = 124;
|
||||||
|
}
|
||||||
|
else if (tag == "emergency")
|
||||||
|
{
|
||||||
|
r = 250;
|
||||||
|
g = 250;
|
||||||
|
b = 255;
|
||||||
|
}
|
||||||
|
else if (tag == "unclassified" || tag == "emergency" || tag == "residential" || tag == "service" || tag == "traffic_island")
|
||||||
|
{
|
||||||
|
r = 15;
|
||||||
|
g = 15;
|
||||||
|
b = 20;
|
||||||
|
}
|
||||||
|
else if (tag == "bus") {
|
||||||
|
r = 150;
|
||||||
|
g = 150;
|
||||||
|
b = 150;
|
||||||
|
}
|
||||||
|
else if (tag == "reserved") { // TODO: Not a keyword I'm aware of
|
||||||
|
r = 0; g = 0; b = 0;
|
||||||
|
visible = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
tag = relation->GetTag("area:railway");
|
||||||
|
if (tag != "")
|
||||||
|
{
|
||||||
|
if (tag == "tram") {
|
||||||
|
r = 150;
|
||||||
|
g = 150;
|
||||||
|
b = 150;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
tag = relation->GetTag("bridge:support");
|
||||||
|
if (tag != "")
|
||||||
|
{
|
||||||
|
r = 184;
|
||||||
|
g = 184;
|
||||||
|
b = 184;
|
||||||
|
}
|
||||||
|
|
||||||
|
tag = relation->GetTag("tunnel");
|
||||||
|
if (tag == "yes")
|
||||||
|
{
|
||||||
|
r = 240;
|
||||||
|
g = 240;
|
||||||
|
b = 255;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (r == 255 && b == 255) {
|
||||||
|
std::cout << relation->id << std::endl;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Multipolygon::SetColor(int r, int g, int b)
|
||||||
|
{
|
||||||
|
this->r = r;
|
||||||
|
this->g = g;
|
||||||
|
this->b = b;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Multipolygon::Draw(SDL_Renderer* renderer)
|
||||||
|
{
|
||||||
|
if (!visible)
|
||||||
|
return;
|
||||||
|
|
||||||
|
for (const Polygon& polygon : polygons) {
|
||||||
|
switch(rendering)
|
||||||
|
{
|
||||||
|
case RenderType::FILL:
|
||||||
|
for (int i = 0; i < polygon.indices.size(); i += 3) // Be a graphics card
|
||||||
|
{
|
||||||
|
|
||||||
|
filledTrigonRGBA(renderer,
|
||||||
|
polygon.vertices[polygon.indices[i + 0]].x, polygon.vertices[polygon.indices[i + 0]].y,
|
||||||
|
polygon.vertices[polygon.indices[i + 1]].x, polygon.vertices[polygon.indices[i + 1]].y,
|
||||||
|
polygon.vertices[polygon.indices[i + 2]].x, polygon.vertices[polygon.indices[i + 2]].y,
|
||||||
|
r, g, b, 255
|
||||||
|
);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case RenderType::OUTLINE:
|
||||||
|
for(int i = 0; i < polygon.segments.size(); i += 2)
|
||||||
|
{
|
||||||
|
thickLineRGBA(renderer,
|
||||||
|
polygon.vertices[polygon.segments[i + 0]].x, polygon.vertices[polygon.segments[i + 0]].y,
|
||||||
|
polygon.vertices[polygon.segments[i + 1]].x, polygon.vertices[polygon.segments[i + 1]].y,
|
||||||
|
5, r, g, b, 255
|
||||||
|
);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case RenderType::INDOOR:
|
||||||
|
for (int i = 0; i < polygon.indices.size(); i += 3) // Be a graphics card
|
||||||
|
{
|
||||||
|
|
||||||
|
filledTrigonRGBA(renderer,
|
||||||
|
polygon.vertices[polygon.indices[i + 0]].x, polygon.vertices[polygon.indices[i + 0]].y,
|
||||||
|
polygon.vertices[polygon.indices[i + 1]].x, polygon.vertices[polygon.indices[i + 1]].y,
|
||||||
|
polygon.vertices[polygon.indices[i + 2]].x, polygon.vertices[polygon.indices[i + 2]].y,
|
||||||
|
r, g, b, 255
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int i = 0; i < polygon.segments.size(); i += 2)
|
||||||
|
{
|
||||||
|
lineRGBA(renderer,
|
||||||
|
polygon.vertices[polygon.segments[i + 0]].x, polygon.vertices[polygon.segments[i + 0]].y,
|
||||||
|
polygon.vertices[polygon.segments[i + 1]].x, polygon.vertices[polygon.segments[i + 1]].y,
|
||||||
|
10, 10, 15, 255
|
||||||
|
);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in a new issue