Commit a7fbe32a authored by Martin Kröning's avatar Martin Kröning

Initial code drop

parent 4063b95e
BasedOnStyle: LLVM
---
Checks: 'bugprone-*,cppcoreguidelines-*,clang-analyzer-*,clang-diagnostic-*,llvm-*,modernize-*,performance-*,portability-*,readability-*'
WarningsAsErrors: 'bugprone-*,cppcoreguidelines-*,clang-analyzer-*,clang-diagnostic-*,llvm-*,modernize-*,performance-*,portability-*,readability-*'
FormatStyle: file
...
# top-most EditorConfig file
root = true
# Unix-style newlines with a newline ending every file
[*]
end_of_line = lf
insert_final_newline = true
trim_trailing_whitespace = true
charset = utf-8
indent_style = space
# Autodetect text files
* text=auto
# Force the following filetypes to have unix eols, so Windows does not break them
*.* text eol=lf
/build*
/subprojects/GSL-2.0.0
/subprojects/packagecache
# PI2 View
The GUI library for showing the Map of the Praktikum Informatik 2
\ No newline at end of file
The GUI library for showing the Map of the Praktikum Informatik 2
## Dependencies
* [Meson](https://mesonbuild.com/Getting-meson.html)
* [gtkmm](https://www.gtkmm.org/en/download.html)
* [Boost](https://www.boost.org/)
project('pi2-view', ['cpp', 'c'],
license: 'GPL3',
meson_version: '>=0.47.0',
version: '1.0-SNAPSHOT',
default_options : ['warning_level=3', 'werror=true', 'cpp_std=c++17', 'c_std=c11']
)
microsoft_gsl_proj = subproject('microsoft-gsl')
microsoft_gsl_dep = microsoft_gsl_proj.get_variable('microsoft_gsl_dep')
subdir('pi2-view')
subdir('pi2-demo')
clangtidy = find_program('clang-tidy', required: false)
if clangtidy.found()
run_target('tidy',
command : 'scripts/tidy.sh')
endif
iwyu_tool = find_program('iwyu_tool', required: false)
if iwyu_tool.found()
run_target('iwyu',
command : 'scripts/iwyu.sh')
endif
KREUZUNG Kr1 0 680 40
KREUZUNG Kr2 1000 680 300
KREUZUNG Kr3 0 680 570
KREUZUNG Kr4 0 320 300
STRASSE Kr1 Kr2 W12 W21 40 1 1 2 680 40 680 300
STRASSE Kr2 Kr3 W23a W32a 115 3 0 6 680 300 850 300 970 390 970 500 850 570 680 570
STRASSE Kr2 Kr3 W23b W32b 40 1 1 2 680 300 680 570
STRASSE Kr2 Kr4 W24 W42 55 1 1 2 680 300 320 300
STRASSE Kr3 Kr4 W34 W43 85 3 0 5 680 570 500 570 350 510 320 420 320 300
STRASSE Kr4 Kr4 W44a W44b 130 2 0 7 320 300 320 150 200 60 80 90 70 250 170 300 320 300
PKW Trabant 100 6 50 Kr1 2.0
PKW Mercedes 180 12 60 Kr1 2.5
FAHRRAD Peugeot 40 Kr1 4
PKW Porsche 240 14.5 70 Kr1 3.3
FAHRRAD BMX 24 Kr1 1.5
PKW Ferrari 250 15 100 Kr1 4.25
KREUZUNG Kr1 500 50 500
KREUZUNG Kr2 0 300 500
KREUZUNG Kr3 0 300 700
KREUZUNG Kr4 0 600 150
KREUZUNG Kr5 0 600 500
KREUZUNG Kr6 0 850 50
KREUZUNG Kr7 200 850 500
KREUZUNG Kr8 1000 850 850
STRASSE Kr1 Kr6 Weg16 Weg61 220 1 0 3 50 500 50 50 850 50
STRASSE Kr1 Kr2 Weg12 Weg21 40 3 1 2 50 500 300 500
STRASSE Kr1 Kr8 Weg18 Weg81 180 3 0 3 50 500 50 850 850 850
STRASSE Kr2 Kr2 Weg22a Weg22b 80 1 1 6 300 500 200 350 250 250 350 250 400 350 300 500
STRASSE Kr2 Kr5 Weg25 Weg52 40 3 1 2 300 500 600 500
STRASSE Kr2 Kr3 Weg23 Weg32 30 3 1 2 300 500 300 700
STRASSE Kr4 Kr5 Weg45b Weg54b 60 3 1 5 600 150 550 150 500 200 500 300 600 500
STRASSE Kr5 Kr4 Weg54a Weg45a 60 3 1 5 600 500 700 300 700 200 650 150 600 150
STRASSE Kr5 Kr8 Weg58 Weg85 70 3 1 2 600 500 850 850
STRASSE Kr6 Kr7 Weg67 Weg76 50 3 1 2 850 50 850 500
STRASSE Kr7 Kr8 Weg78 Weg87 50 3 1 2 850 500 850 850
STRASSE Kr8 Kr6 Weg86 Weg68 120 2 1 4 850 850 950 850 950 50 850 50
STRASSE Kr5 Kr7 Weg57 Weg75 30 3 1 2 600 500 850 500
PKW Trabant 100 6 50 Kr3 2.0
PKW Mercedes 180 12 60 Kr3 2.5
FAHRRAD Peugeot 40 Kr7 4
PKW Porsche 240 14.5 70 Kr7 3.3
FAHRRAD BMX 24 Kr1 1.5
PKW Ferrari 250 15 100 Kr6 4.25
#pragma once
#include "Vehicle.hpp"
#include <string>
class MapAppABIWrapper;
class Bicycle : public Vehicle {
public:
Bicycle(std::string name, double topSpeed, double timeOfStart, double time);
void draw(MapAppABIWrapper &mapApp, const std::string &laneName,
double laneLength, double speedLimit) const override;
double getSpeed(double speedLimit) const override;
};
#pragma once
#include "Vehicle.hpp"
#include <string>
class MapAppABIWrapper;
class Car : public Vehicle {
public:
/// The fuel tank is half full at construction
Car(std::string name, double topSpeed, double timeOfStart, double fuelConsumption,
double fuelCapacity, double time);
void draw(MapAppABIWrapper &mapApp, const std::string &laneName,
double laneLength, double speedLimit) const override;
double getSpeed(double speedLimit) const override;
void process(double time, double maximumDistanceOnLane,
double speedLimit) override;
/// Refuels the vehicle provided the \p availableFuel in l
/// \returns The amount of fuel in l that has been taken
double refuel(double availableFuel);
private:
/// Fuel consumption in l/100km
double fuelConsumption;
/// Fuel capacity in l
double fuelCapacity;
/// Remaining fuel in l
double fuel;
};
#pragma once
#include <functional>
#include <vector>
/// Wraps an object and defers modifying actions
/// until explicitly applying them
///
/// \param T The type of the wrapped object
template <typename T> class DeferralActionWrapper {
public:
using ValueType = T;
using Function = std::function<void(ValueType &)>;
/// Constructs a wrapper around a default constructed object
DeferralActionWrapper() = default;
/// Constructs a wrapper around a given \p object
explicit DeferralActionWrapper(ValueType object)
: wrappedObject(std::move(object)) {}
/// Returns a the wrapped object
ValueType &get() { return wrappedObject; }
const ValueType &get() const { return wrappedObject; }
/// Enqueues an \p action
///
/// Caution: Be sure to work on a reference to modify the wrapped object!
void enqueue(Function action) {
deferredActions.push_back(std::move(action));
}
/// Applies pending modifying actions
void apply() {
for (auto &&action : deferredActions) {
action(wrappedObject);
}
deferredActions.clear();
}
private:
ValueType wrappedObject;
std::vector<Function> deferredActions;
};
#pragma once
#include "Lane.hpp"
#include "Named.hpp"
#include <memory>
#include <random>
#include <string>
#include <vector>
class Vehicle;
class MapAppABIWrapper;
class Junction : public Named {
public:
/// Creates two lanes between \p junctionA and \p junctionB
static void connect(const std::weak_ptr<Junction> &junctionA,
const std::weak_ptr<Junction> &junctionB,
const std::string &laneAToBName,
const std::string &laneBToAName, double length,
double speedLimit, bool noPassing);
Junction(Junction &&other) noexcept;
Junction &operator=(Junction &&other) noexcept;
Junction(std::string name, double fuelAmount);
void processVehicles(double time);
void drawVehicles(MapAppABIWrapper &mapApp) const;
void createCar(std::string name, double topSpeed, double fuelConsumption,
double fuelCapacity, double timeOfStart, double time);
void createBicycle(std::string name, double topSpeed, double timeOfStart,
double time);
void acceptVehicle(std::unique_ptr<Vehicle> vehicle,
const std::string &prohibitedLaneName);
private:
/// Mersenne Twister random number generator
/// for selection in randomOutboundLaneExcept
static std::mt19937 gen;
std::vector<Lane> outboundLanes;
/// The amount of fuel in l in the filling station
double fuelAmount;
/// Refuels the given vehicle using the filling station
void fillUp(Vehicle &fahrzeug);
Lane &randomOutboundLane();
Lane &randomOutboundLaneExcept(const std::string &laneName);
};
#pragma once
#include "Named.hpp"
#include "Vehicle.hpp"
#include <memory>
#include <string>
#include <vector>
class MapAppABIWrapper;
class Junction;
class Lane : public Named {
public:
Lane(Lane &&other) noexcept;
Lane(std::string name, std::string oppositeLaneName, double length,
double speedLimit, bool noPassing,
std::weak_ptr<Junction> destinationJunction);
void drawVehicles(MapAppABIWrapper &mapApp) const;
void processVehicles(double time);
void acceptVehicle(std::unique_ptr<Vehicle> vehicle);
void createCar(std::string name, double maximumVelocity,
double fuelConsumption, double fuelCapacity,
double timeOfStart, double time);
void createBicycle(std::string name, double maximumVelocity,
double timeOfStart, double time);
private:
/// Length property in km
double length;
std::weak_ptr<Junction> destinationJunction;
std::string oppositeLaneName;
double speedLimit;
bool noPassing;
std::vector<std::unique_ptr<Vehicle>> vehicles;
};
#pragma once
#include "MapAppABIWrapper.hpp"
#include <chrono>
#include <iosfwd>
#include <memory>
#include <string>
#include <vector>
class Junction;
class Map {
public:
explicit Map(std::istream &is);
void simulate(std::chrono::seconds duration, double speedFactor,
double frequency);
private:
double time;
std::vector<std::shared_ptr<Junction>> junctions;
MapAppABIWrapper mapApp;
std::weak_ptr<Junction> getJunction(const std::string &name);
/// Required format:
/// `name` `fuelAmount` `x` `y`
void extractJunctionAndDraw(std::istream &is, MapAppABIWrapper &mapApp);
/// Required format:
/// `nameJunctionA` `nameJunctionB` `nameLaneAToB` `nameLaneBToA` `length in km`
/// `speedLimit in {1,2,3}` `noPassing` `coordinateCount` `coordinates...`
void extractRoadAndDraw(std::istream &is, MapAppABIWrapper &mapApp);
/// Required format:
/// `name` `topSpeed` `nameStartJunction` `timeOfStart`
void extractBicycle(std::istream &is);
/// Required format:
/// `name` `topSpeed` `fuelConsumption` `fuelCapacity` `nameStartJunction`
/// `timeOfStart`
void extractCar(std::istream &is);
};
#pragma once
#include <chrono>
#include <string>
#include <vector>
struct MapApp;
class MapAppABIWrapper {
public:
MapAppABIWrapper();
virtual ~MapAppABIWrapper();
void addJunction(double x, double y);
void addRoad(const std::string &laneThereName,
const std::string &laneBackName,
const std::vector<double> &coordinates);
void addOrReplaceVehicle(const std::string &vehicleName,
const std::string &laneName, double positionOnLane,
double speed, double remainingFuel, double red,
double green, double blue);
void setDurationLabel(std::chrono::minutes minutes);
private:
MapApp *mapApp;
};
#pragma once
#include <string>
class Named {
public:
Named(const Named &other);
Named(Named &&other) noexcept;
Named &operator=(const Named &other);
Named &operator=(Named &&other) noexcept;
virtual ~Named() = 0;
std::string getName() const;
protected:
explicit Named(std::string name);
private:
std::string name;
};
#pragma once
#include "Named.hpp"
#include <string>
class MapAppABIWrapper;
class Vehicle : public Named {
public:
// Draws the vehicle on the provided \p mapApp on the specified \p laneName
// which has a \p laneLength and a \p speedLimit
virtual void draw(MapAppABIWrapper &mapApp, const std::string &laneName,
double laneLength, double speedLimit) const = 0;
/// \returns The current speed in km/h
virtual double getSpeed(double speedLimit) const = 0;
/// Updates the total traveled distance, the total traveled time and
/// the time of this tick
virtual void process(double time, double maximumDistanceOnLane,
double speedLimit);
double getDistanceOnLane() const;
void resetDistanceOnLane();
protected:
Vehicle(std::string name, double topSpeed, double timeOfStart, double time);
double getTopSpeed() const;
double getGesamtStrecke() const;
bool isParking() const;
private:
/// Maximum speed in km/h
double topSpeed;
/// Total travel distance in km
double odometer;
/// Current distance on lane in km
double distanceOnLane;
bool parking;
double timeOfStart;
double timeOfLastProcessing;
};
pi2_demo_inc = include_directories('include')
pi2_demo_src = files(
'src/Named.cpp',
'src/Bicycle.cpp',
'src/Vehicle.cpp',
'src/Junction.cpp',
'src/Car.cpp',
'src/Lane.cpp',
'src/Map.cpp',
'src/main.cpp',
'src/MapAppABIWrapper.cpp'
)
boost_po_dep = dependency('boost', modules : ['program_options'])
executable('pi2-demo', pi2_demo_src,
include_directories: pi2_demo_inc,
dependencies: [pi2_view_dep, boost_po_dep],
install: true
)
install_headers('include/MapAppABIWrapper.hpp', 'src/MapAppABIWrapper.cpp', subdir : 'pi2-view')
#include "Bicycle.hpp"
#include "MapAppABIWrapper.hpp"
#include <algorithm>
#include <cmath>
#include <utility>
Bicycle::Bicycle(std::string name, const double topSpeed,
const double timeOfStart, const double time)
: Vehicle(std::move(name), topSpeed, timeOfStart, time) {}
void Bicycle::draw(MapAppABIWrapper &mapApp, const std::string &laneName,
const double laneLength, const double speedLimit) const {
const auto positionOnLane = getDistanceOnLane() / laneLength;
mapApp.addOrReplaceVehicle(getName(), laneName, positionOnLane,
getSpeed(speedLimit), 0, 0, 1, 0);
}
double Bicycle::getSpeed(const double speedLimit) const {
auto const slowingSpeed =
getTopSpeed() * std::pow(0.9, std::floor(getGesamtStrecke() / 20));
return isParking() ? 0 : std::min(std::max(slowingSpeed, 12.0), speedLimit);
}
#include "Car.hpp"
#include "MapAppABIWrapper.hpp"
#include <algorithm>
#include <utility>
Car::Car(std::string name, const double topSpeed, const double timeOfStart,
const double fuelConsumption, const double fuelCapacity,
const double time)
: Vehicle(std::move(name), topSpeed, timeOfStart, time),
fuelConsumption(fuelConsumption), fuelCapacity(fuelCapacity),
fuel(fuelCapacity / 2) {}
void Car::draw(MapAppABIWrapper &mapApp, const std::string &laneName,
const double laneLength, const double speedLimit) const {
const auto positionOnLane = getDistanceOnLane() / laneLength;
mapApp.addOrReplaceVehicle(getName(), laneName, positionOnLane,
getSpeed(speedLimit), fuel, 1, 0, 0);
}
double Car::getSpeed(const double speedLimit) const {
const auto potentialSpeed = std::min(speedLimit, getTopSpeed());
return isParking() || fuel <= 0 ? 0 : potentialSpeed;
}
void Car::process(const double time, const double maximumDistanceOnLane,
const double speedLimit) {
const auto oldDistance = getGesamtStrecke();
Vehicle::process(time, maximumDistanceOnLane, speedLimit);
fuel -= fuelConsumption * (getGesamtStrecke() - oldDistance) / 100;
}
double Car::refuel(const double availableFuel) {
const auto refueledAmount = std::min(availableFuel, fuelCapacity - fuel);
fuel += refueledAmount;
return refueledAmount;
}
#include "Junction.hpp"
#include "Car.hpp"
#include "Vehicle.hpp"
#include <memory>
#include <random>
#include <typeinfo>
#include <utility>
class MapAppABIWrapper;
void Junction::connect(const std::weak_ptr<Junction> &junctionA,
const std::weak_ptr<Junction> &junctionB,
const std::string &laneAToBName,
const std::string &laneBToAName, const double length,
const double speedLimit, const bool noPassing) {
Lane laneAToB(laneAToBName, laneBToAName, length, speedLimit, noPassing,
junctionB);
Lane laneBToA(laneBToAName, laneAToBName, length, speedLimit, noPassing,
junctionA);
junctionA.lock()->outboundLanes.push_back(std::move(laneAToB));
junctionB.lock()->outboundLanes.push_back(std::move(laneBToA));
}
// NOLINTNEXTLINE(cppcoreguidelines-pro-type-member-init)
Junction::Junction(Junction &&other) noexcept = default;
Junction &Junction::operator=(Junction &&other) noexcept = default;
Junction::Junction(std::string name, const double fuelAmount)
: Named(std::move(name)), fuelAmount(fuelAmount) {}
void Junction::processVehicles(const double time) {
for (auto &&lane : outboundLanes) {
lane.processVehicles(time);
}
}
void Junction::drawVehicles(MapAppABIWrapper &mapApp) const {
for (auto &&weg : outboundLanes) {
weg.drawVehicles(mapApp);
}
}
void Junction::createCar(std::string name, const double topSpeed,
const double fuelConsumption,
const double fuelCapacity, const double timeOfStart,
const double time) {
randomOutboundLane().createCar(std::move(name), topSpeed, fuelConsumption,
fuelCapacity, timeOfStart, time);
}
void Junction::createBicycle(std::string name, const double topSpeed,
const double timeOfStart, const double time) {
randomOutboundLane().createBicycle(std::move(name), topSpeed, timeOfStart,
time);
}
void Junction::acceptVehicle(std::unique_ptr<Vehicle> vehicle,
const std::string &prohibitedLaneName) {
fillUp(*vehicle);
vehicle->resetDistanceOnLane();
randomOutboundLaneExcept(prohibitedLaneName)
.acceptVehicle(std::move(vehicle));
}
std::mt19937 Junction::gen([]() {
std::random_device rd;
return rd();
}());
void Junction::fillUp(Vehicle &fahrzeug) {
try {
auto &car = dynamic_cast<Car &>(fahrzeug);
fuelAmount -= car.refuel(fuelAmount);
} catch (const std::bad_cast &e) {
}
}
Lane &Junction::randomOutboundLane() {
std::uniform_int_distribution<> dis(0, outboundLanes.size() - 1);
return outboundLanes.at(dis(gen));
}
Lane &Junction::randomOutboundLaneExcept(const std::string &laneName) {
auto &randomLane = randomOutboundLane();
return randomLane.getName() != laneName || outboundLanes.size() <= 1
? randomLane
: randomOutboundLaneExcept(laneName);
}
#include "Lane.hpp"
#include "Bicycle.hpp"
#include "Car.hpp"
#include "Junction.hpp"
#include "Vehicle.hpp"
#include <algorithm>
#include <memory>
#include <utility>
class MapAppABIWrapper;
// NOLINTNEXTLINE(cppcoreguidelines-pro-type-member-init)
Lane::Lane(Lane &&other) noexcept = default;
Lane::Lane(std::string name, std::string oppositeLaneName, const double length,
const double speedLimit, const bool noPassing,
std::weak_ptr<Junction> destinationJunction)
: Named(std::move(name)), length(length),
destinationJunction(std::move(destinationJunction)),
oppositeLaneName(std::move(oppositeLaneName)), speedLimit(speedLimit),
noPassing(noPassing) {}
void Lane::drawVehicles(MapAppABIWrapper &mapApp) const {
for (auto &&fahrzeug : vehicles) {
fahrzeug->draw(mapApp, getName(), length, speedLimit);
}
}
void Lane::processVehicles(const double time) {
const auto furthestFirstComparator = [](const auto &vehicleA,
const auto &vehicleB) {
return vehicleA->getDistanceOnLane() > vehicleB->getDistanceOnLane();
};
std::sort(vehicles.begin(), vehicles.end(), furthestFirstComparator);
double maximumPosition = length;
for (auto &&fahrzeug : vehicles) {
fahrzeug->process(time, maximumPosition, speedLimit);
if (noPassing && fahrzeug->getSpeed(speedLimit) != 0) {
maximumPosition = fahrzeug->getDistanceOnLane();
}
}
std::sort(vehicles.begin(), vehicles.end(), furthestFirstComparator);
while (!vehicles.empty() && length <= vehicles.at(0)->getDistanceOnLane()) {
destinationJunction.lock()->acceptVehicle(std::move(vehicles.front()),
oppositeLaneName);
vehicles.erase(vehicles.begin());
}
}
void Lane::acceptVehicle(std::unique_ptr<Vehicle> vehicle) {
vehicles.push_back(std::move(vehicle));
}
void Lane::createCar(std::string name, const double maximumVelocity,
const double fuelConsumption, const double fuelCapacity,
const double timeOfStart, const double time) {
vehicles.push_back(std::make_unique<Car>(std::move(name), maximumVelocity,
timeOfStart, fuelConsumption,
fuelCapacity, time));
}
void Lane::createBicycle(std::string name, const double maximumVelocity,
const double timeOfStart, const double time) {
vehicles.push_back(std::make_unique<Bicycle>(std::move(name), maximumVelocity,
timeOfStart, time));
}
#include "Map.hpp"
#include "Junction.hpp"
#include "MapAppABIWrapper.hpp"
#include <algorithm>
#include <chrono>
#include <limits>
#include <memory>
#include <ratio>
#include <sstream>
#include <stddef.h>
#include <stdexcept>
#include <string>
#include <thread>
#include <utility>
#include <vector>
Map::Map(std::istream &is) : time(0) {
std::string type;
while (is >> type) {
if (type == "KREUZUNG") {
extractJunctionAndDraw(is, mapApp);
} else if (type == "STRASSE") {
extractRoadAndDraw(is, mapApp);
} else if (type == "PKW") {
extractCar(is);
} else if (type == "FAHRRAD") {
extractBicycle(is);
}