Attempted to implement map static data

This commit is contained in:
James Shiffer 2023-10-30 00:53:00 -07:00
parent e967653526
commit 4ec27df5a1
19 changed files with 464 additions and 40 deletions

2
.gitignore vendored
View File

@ -1,4 +1,6 @@
# ---> C++ # ---> C++
FemMaps
# Prerequisites # Prerequisites
*.d *.d

View File

@ -0,0 +1,24 @@
CC = g++
CFLAGS = -g -Wall -Wextra
LIBS = `pkg-config --cflags --libs caca libcurl`
OUT = obj
SRC = map
OBJS = $(OUT)/SigalertMapProvider.o $(OUT)/SigalertRoad.o $(OUT)/SigalertRoadSection.o $(OUT)/SigalertRoadSensor.o $(OUT)/SigalertTypes.o
PROG = FemMaps
EXECUTABLES = tui/$(PROG)
.PHONY: all clean tui
all: $(EXECUTABLES)
$(OUT)/%.o: $(SRC)/%.cpp
mkdir -p $(OUT)
$(CC) $(CFLAGS) -c $< -o $@
tui/$(PROG): $(OBJS) tui/*.cpp
$(CC) $(LIBS) $^ -o $@
tui: tui/$(PROG)
clean:
rm -f $(EXECUTABLES) $(OBJS)

View File

@ -4,6 +4,15 @@ At FemboyFinancial we love maps! The code in this repo will be used to power a l
showing traffic conditions on various Bay Area highways. Until the physical wall display is made, though, a TUI frontend showing traffic conditions on various Bay Area highways. Until the physical wall display is made, though, a TUI frontend
can be used. can be used.
## Dependencies
* IntervalTree (included)
* JSON for Modern C++ (included)
TUI only:
* libcaca
## Building ## Building
```sh ```sh

View File

@ -1,11 +0,0 @@
//
// Created by scoliono on 10/14/23.
//
#include <iostream>
int main(int argc, char** argv)
{
std::cout << "FemMaps" << std::endl;
return 0;
}

View File

@ -5,14 +5,14 @@
#ifndef FEMMAPS_MAPPROVIDER_H #ifndef FEMMAPS_MAPPROVIDER_H
#define FEMMAPS_MAPPROVIDER_H #define FEMMAPS_MAPPROVIDER_H
#include "Road.h"
#include <map>
class MapProvider { class MapProvider {
public: public:
virtual void refresh() = 0; virtual void refreshData() = 0;
virtual void roadSections() = 0; virtual const std::map<int, Road*>& roads() const = 0;
virtual void roads() = 0;
}; };

21
map/Road.h Normal file
View File

@ -0,0 +1,21 @@
//
// Created by scoliono on 10/15/23.
//
#ifndef FEMMAPS_ROAD_H
#define FEMMAPS_ROAD_H
#include "../include/IntervalTree.h"
#include "RoadSensor.h"
class Road {
public:
virtual const char *name() const = 0;
virtual int id() const = 0;
virtual const IntervalTree<int, int>& speedLimits() const = 0;
virtual const std::vector<RoadSensor*>& sensors() const = 0;
};
#endif //FEMMAPS_ROAD_H

View File

@ -9,7 +9,8 @@ enum RoadDirection {
NORTH, NORTH,
EAST, EAST,
SOUTH, SOUTH,
WEST WEST,
UNKNOWN
}; };
#endif //FEMMAPS_ROADDIRECTION_H #endif //FEMMAPS_ROADDIRECTION_H

20
map/RoadSensor.h Normal file
View File

@ -0,0 +1,20 @@
//
// Created by scoliono on 10/15/23.
//
#ifndef FEMMAPS_ROADSENSOR_H
#define FEMMAPS_ROADSENSOR_H
class Road;
class RoadSensor {
public:
virtual const Road* road() = 0;
virtual const int* pos() = 0;
virtual int speed() = 0;
virtual int speedLimit() = 0;
};
#endif //FEMMAPS_ROADSENSOR_H

View File

@ -3,3 +3,124 @@
// //
#include "SigalertMapProvider.h" #include "SigalertMapProvider.h"
#include "SigalertRoadSensor.h"
#include <iostream>
#include <stdlib.h>
#include <string.h>
using nlohmann::json;
SigalertMapProvider::SigalertMapProvider()
{
m_curl = curl_easy_init();
}
SigalertMapProvider::~SigalertMapProvider()
{
curl_easy_cleanup(m_curl);
if (m_static_data.memory)
free(m_static_data.memory);
if (m_current_data.memory)
free(m_current_data.memory);
for (auto section : m_allsections)
delete section;
for (auto sensor : m_allsensors)
delete sensor;
}
size_t SigalertMapProvider::curl_write_callback(void* contents, size_t size, size_t nmemb, void* userp)
{
size_t realsize = size * nmemb;
struct MemoryStruct* mem = static_cast<struct MemoryStruct*>(userp);
char* ptr = static_cast<char*>(realloc(mem->memory, mem->size + realsize + 1));
if (!ptr)
{
/* out of memory! */
std::cerr << "not enough memory (realloc returned NULL)" << std::endl;
return 0;
}
mem->memory = ptr;
memcpy(&(mem->memory[mem->size]), contents, realsize);
mem->size += realsize;
mem->memory[mem->size] = 0;
return realsize;
}
void SigalertMapProvider::refreshData()
{
curl_easy_setopt(m_curl, CURLOPT_URL, SigalertMapProvider::STATIC_DATA_URL);
curl_easy_setopt(m_curl, CURLOPT_WRITEFUNCTION, &SigalertMapProvider::curl_write_callback);
curl_easy_setopt(m_curl, CURLOPT_WRITEDATA, (void*)&m_static_data);
curl_easy_setopt(m_curl, CURLOPT_USERAGENT, "libcurl-agent/1.0");
CURLcode res = curl_easy_perform(m_curl);
if (res != CURLE_OK)
{
std::cerr << "request for static map data failed: " << curl_easy_strerror(res) << std::endl;
return;
}
try
{
m_static_json = json::parse(m_static_data.memory);
}
catch (json::parse_error& e)
{
std::cerr << "JSON error while parsing static map data: " << e.what() << std::endl;
return;
}
populateRoadSensors();
populateRoads();
populateRoadSections();
}
/**
* Expects road sensors to be populated first.
*/
void SigalertMapProvider::populateRoads()
{
auto roads = m_static_json.at("roads");
for (auto& el : roads.items())
{
SigalertRoadJson road_json = el.value();
int i = atoi(el.key().c_str());
SigalertRoad* road = new SigalertRoad(i, road_json);
m_roads.insert(std::pair<int, Road*>(i, static_cast<Road*>(road)));
road->populateSensors(m_allsensors);
}
}
/**
* Expects roads to be populated first.
*/
void SigalertMapProvider::populateRoadSections()
{
auto sections = m_static_json.at("roadSections");
for (auto& el : sections.items())
{
SigalertRoadSectionJson section_json = el.value();
SigalertRoad* road = dynamic_cast<SigalertRoad*>(m_roads[section_json.road_id]);
SigalertRoadSection* section = new SigalertRoadSection(section_json, road);
m_allsections.push_back(section);
road->addSection(section);
}
}
void SigalertMapProvider::populateRoadSensors()
{
auto names = m_static_json.at("sensorNames");
auto pos = m_static_json.at("sensorPositions");
//auto speeds = m_current_json.at("speeds");
size_t idx = 0;
for (auto& el : names.items())
{
SigalertRoadSensor* sensor = new SigalertRoadSensor(idx, el.value(), pos[idx], -1);
m_allsensors.push_back(sensor);
idx++;
}
}

View File

@ -7,19 +7,45 @@
#include "MapProvider.h" #include "MapProvider.h"
#include "SigalertRoad.h" #include "SigalertRoad.h"
#include "SigalertRoadSection.h"
#include "../include/json.hpp" #include "../include/json.hpp"
#include <curl/curl.h>
#include <vector>
class SigalertMapProvider : public MapProvider { class SigalertMapProvider : public MapProvider {
public: public:
SigalertMapProvider(); SigalertMapProvider();
~SigalertMapProvider();
void refreshData(); void refreshData();
void roadSections(); inline const std::vector<SigalertRoadSection*> roadSections() const { return m_allsections; }
void roads(); inline const std::vector<SigalertRoadSensor*> roadSensors() const { return m_allsensors; }
inline const std::map<int, Road*>& roads() const { return m_roads; }
private: private:
static constexpr const char* STATIC_DATA_URL = "https://cdn-static.sigalert.com/240/Zip/RegionInfo/NoCalStatic.json";
static constexpr const char* CURRENT_DATA_URL = "https://www.sigalert.com/Data/NoCal/0~j/NoCalData.json";
void populateRoads(); void populateRoads();
std::map<int, SigalertRoad> m_roads; void populateRoadSections();
void populateRoadSensors();
std::map<int, Road*> m_roads;
std::vector<SigalertRoadSection*> m_allsections;
std::vector<SigalertRoadSensor*> m_allsensors;
CURL* m_curl;
struct MemoryStruct {
char* memory;
size_t size;
};
size_t curl_write_callback(void* contents, size_t size, size_t nmemb, void* userp);
MemoryStruct m_static_data;
nlohmann::json m_static_json;
MemoryStruct m_current_data;
nlohmann::json m_current_json;
}; };

View File

@ -3,3 +3,32 @@
// //
#include "SigalertRoad.h" #include "SigalertRoad.h"
#include "SigalertRoadSensor.h"
#include "../include/IntervalTree.h"
#include <utility>
SigalertRoad::SigalertRoad(int id, const SigalertRoadJson& json)
: m_id(id), m_name(json.name), m_section_idx_range{json.section_start_idx, json.section_end_idx}
{
std::vector<Interval<int, int>> intervals;
for (auto sensor : json.sensors)
{
intervals.push_back(Interval<int, int>(sensor[0], sensor[1], sensor[2]));
}
m_sensor_speedlimits = IntervalTree<int, int>(std::move(intervals));
}
void SigalertRoad::addSection(SigalertRoadSection* section)
{
m_sections.push_back(section);
}
void SigalertRoad::populateSensors(const std::vector<SigalertRoadSensor*>& sensors)
{
for (int i = m_section_idx_range[0]; i <= m_section_idx_range[1]; ++i)
{
m_sensors.push_back(sensors[i]);
sensors[i]->setRoad(this);
}
}

View File

@ -5,28 +5,39 @@
#ifndef FEMMAPS_SIGALERTROAD_H #ifndef FEMMAPS_SIGALERTROAD_H
#define FEMMAPS_SIGALERTROAD_H #define FEMMAPS_SIGALERTROAD_H
#include "SigalertRoadSection.h" #include "Road.h"
#include "SigalertRoadSensor.h" #include "RoadSensor.h"
#include "SigalertTypes.h"
#include "../include/IntervalTree.h" #include "../include/IntervalTree.h"
#include "../include/json.hpp"
#include <string>
#include <vector>
class SigalertRoad {
class SigalertRoadSection;
class SigalertRoadSensor;
class SigalertRoad : public Road {
public: public:
SigalertRoad(); SigalertRoad(int id, const SigalertRoadJson& json);
const std::vector<SigalertRoadSection>& sections(); inline int id() const { return m_id; }
const std::vector<SigalertRoadSensor>& sensors(); inline const char* name() const { return m_name.c_str(); }
const IntervalTree<int, int>& speedLimits(); inline const std::vector<SigalertRoadSection*>& sections() const { return m_sections; }
int id(); inline const std::vector<RoadSensor*>& sensors() const { return m_sensors; }
inline const IntervalTree<int, int>& speedLimits() const { return m_sensor_speedlimits; }
void addSection(SigalertRoadSection* section);
void populateSensors(const std::vector<SigalertRoadSensor*>& sensors);
private: private:
void populateRoadSections();
void populateRoadSensors();
int m_id; int m_id;
std::string m_name; std::string m_name;
std::vector<SigalertRoadSection> m_sections; std::vector<SigalertRoadSection*> m_sections;
std::vector<SigalertRoadSensor> m_sensors; int m_section_idx_range[2];
std::vector<RoadSensor*> m_sensors;
IntervalTree<int, int> m_sensor_speedlimits; IntervalTree<int, int> m_sensor_speedlimits;
}; };

View File

@ -3,3 +3,29 @@
// //
#include "SigalertRoadSection.h" #include "SigalertRoadSection.h"
#include "SigalertRoad.h"
SigalertRoadSection::SigalertRoadSection(const SigalertRoadSectionJson& json, const SigalertRoad* road)
: m_road(road), m_sensor_idx_range{json.sensor_start_idx, json.sensor_end_idx}
{
if (json.dir == "North")
{
m_dir = NORTH;
}
else if (json.dir == "East")
{
m_dir = EAST;
}
else if (json.dir == "South")
{
m_dir = SOUTH;
}
else if (json.dir == "West")
{
m_dir = WEST;
}
else
{
m_dir = UNKNOWN;
}
}

View File

@ -6,17 +6,19 @@
#define FEMMAPS_SIGALERTROADSECTION_H #define FEMMAPS_SIGALERTROADSECTION_H
#include "RoadDirection.h" #include "RoadDirection.h"
#include "SigalertRoad.h"
#include "SigalertTypes.h"
class SigalertRoadSection { class SigalertRoadSection {
public: public:
SigalertRoadSection(); SigalertRoadSection(const SigalertRoadSectionJson& json, const SigalertRoad* road);
int speedLimit(int sensorIdx); inline RoadDirection direction() { return m_dir; }
RoadDirection direction(); inline const SigalertRoad* road() { return m_road; }
const SigalertRoadSection& road();
private: private:
SigalertRoad* m_road; const SigalertRoad* m_road;
RoadDirection m_dir; RoadDirection m_dir;
int m_sensor_idx_range[2]; int m_sensor_idx_range[2];
}; };

View File

@ -3,3 +3,24 @@
// //
#include "SigalertRoadSensor.h" #include "SigalertRoadSensor.h"
SigalertRoadSensor::SigalertRoadSensor(const int id, const std::string& name, const std::vector<int>& pos, int speed)
: m_id(id), m_name(name), m_pos{pos[0], pos[1]}, m_speed(speed)
{
}
SigalertRoadSensor::~SigalertRoadSensor()
{
}
int SigalertRoadSensor::speedLimit()
{
const IntervalTree<int, int> it = m_road->speedLimits();
auto iv = it.findContained(m_id, m_id);
if (!iv.size())
{
return -1;
}
return iv[0].value;
}

View File

@ -5,17 +5,29 @@
#ifndef FEMMAPS_SIGALERTROADSENSOR_H #ifndef FEMMAPS_SIGALERTROADSENSOR_H
#define FEMMAPS_SIGALERTROADSENSOR_H #define FEMMAPS_SIGALERTROADSENSOR_H
#include "Road.h"
#include "RoadSensor.h"
#include "SigalertRoad.h"
#include <string> #include <string>
class SigalertRoadSensor { class SigalertRoadSensor : public RoadSensor {
public: public:
SigalertRoadSensor(const std::string& name, const int pos[]); SigalertRoadSensor(const int id, const std::string& name, const std::vector<int>& pos, int speed);
virtual ~SigalertRoadSensor();
inline const Road* road() { return static_cast<const Road*>(m_road); }
inline void setRoad(const SigalertRoad* road) { m_road = road; }
inline const char* name() { return m_name.c_str(); }
inline const int* pos() { return m_pos; }
inline int speed() { return m_speed; }
int speedLimit();
private: private:
int m_id;
const SigalertRoad* m_road;
std::string m_name; std::string m_name;
int m_pos[2]; const int m_pos[2];
int m_speed; int m_speed;
}; };

22
map/SigalertTypes.cpp Normal file
View File

@ -0,0 +1,22 @@
//
// Created by scoliono on 10/30/23.
//
#include "SigalertTypes.h"
void from_json(const json& j, SigalertRoadJson& obj)
{
j.at(0).get_to(obj.name);
j.at(1).get_to(obj.section_start_idx);
j.at(2).get_to(obj.section_end_idx);
j.at(3).get_to(obj.sensors);
}
void from_json(const json& j, SigalertRoadSectionJson& obj)
{
j.at(0).get_to(obj.road_id);
j.at(1).get_to(obj.dir);
j.at(2).get_to(obj.name);
j.at(3).get_to(obj.sensor_start_idx);
j.at(4).get_to(obj.sensor_end_idx);
}

33
map/SigalertTypes.h Normal file
View File

@ -0,0 +1,33 @@
//
// Created by scoliono on 10/29/23.
//
#ifndef FEMMAPS_SIGALERTTYPES_H
#define FEMMAPS_SIGALERTTYPES_H
#include "../include/json.hpp"
using nlohmann::json;
struct SigalertRoadJson {
std::string name;
int section_start_idx;
int section_end_idx;
std::vector<std::vector<int>> sensors;
};
struct SigalertRoadSectionJson {
int road_id;
std::string dir;
std::string name;
int sensor_start_idx;
int sensor_end_idx;
};
void from_json(const json& j, SigalertRoadJson& obj);
void from_json(const json& j, SigalertRoadSectionJson& obj);
#endif //FEMMAPS_SIGALERTTYPES_H

55
tui/main.cpp Normal file
View File

@ -0,0 +1,55 @@
//
// Created by scoliono on 10/14/23.
//
#include <iostream>
#include <caca.h>
#include "../map/SigalertMapProvider.h"
#include "../map/SigalertRoadSensor.h"
void caca_display_drivers()
{
const char* const* drivers = caca_get_display_driver_list();
for (int i = 0; drivers[i] != NULL; i += 2)
{
std::cout << drivers[i] << '\t' << drivers[i + 1] << std::endl;
}
}
int main(int argc, char** argv)
{
caca_canvas_t *cv;
caca_display_t *dp;
caca_event_t ev;
dp = caca_create_display_with_driver(NULL, "ncurses");
if (!dp) {
std::cerr << "Failed to create caca display" << std::endl;
return 1;
}
cv = caca_get_canvas(dp);
caca_set_display_title(dp, "Hello!");
caca_set_color_ansi(cv, CACA_BLACK, CACA_WHITE);
caca_put_str(cv, 0, 0, "This is a message");
SigalertMapProvider smp;
smp.refreshData();
int i = 0;
while (i < smp.roadSensors().size())
{
auto sensor = smp.roadSensors()[i];
if (i < smp.roadSensors().size() - 1)
{
auto sensor2 = smp.roadSensors()[i + 1];
caca_draw_thin_line(cv, sensor->pos()[0], sensor->pos()[1], sensor2->pos()[0], sensor2->pos()[1]);
}
else
{
caca_draw_thin_line(cv, sensor->pos()[0], sensor->pos()[1], sensor->pos()[0], sensor->pos()[1]);
}
i += 2;
caca_refresh_display(dp);
}
caca_get_event(dp, CACA_EVENT_KEY_PRESS, &ev, -1);
caca_free_display(dp);
return 0;
}