init
This commit is contained in:
@@ -0,0 +1,10 @@
|
||||
---
|
||||
BasedOnStyle: LLVM
|
||||
---
|
||||
Language: Cpp
|
||||
DerivePointerAlignment: false
|
||||
PointerAlignment: Left
|
||||
ColumnLimit: 140
|
||||
TabWidth: 4
|
||||
IndentWidth: 2
|
||||
...
|
||||
@@ -0,0 +1,25 @@
|
||||
# debug: clangd --check=modules/iue-io/ccsv.h
|
||||
# debug: clangd --check=task1.hpp
|
||||
# debug: clangd --check=task1.test.cpp
|
||||
InlayHints:
|
||||
Enabled: No
|
||||
ParameterNames: Yes
|
||||
DeducedTypes: No
|
||||
---
|
||||
CompileFlags:
|
||||
Add:
|
||||
# - --target=x86_64-w64-windows-gnu
|
||||
# - --target=x86_64-pc-linux-gnu
|
||||
- -Wall
|
||||
- -Wno-unused-function
|
||||
- -Wno-unused-variable
|
||||
---
|
||||
If:
|
||||
PathMatch: [.*\.c, .*\.h]
|
||||
CompileFlags:
|
||||
Add: [-std=c11]
|
||||
---
|
||||
If:
|
||||
PathMatch: [.*\.cpp, .*\.hpp]
|
||||
CompileFlags:
|
||||
Add: [-std=c++20]
|
||||
@@ -0,0 +1,3 @@
|
||||
task1
|
||||
task2
|
||||
task3
|
||||
@@ -0,0 +1,4 @@
|
||||
task1.main.cpp
|
||||
task2.Circle.hpp
|
||||
task2.Polyline.hpp
|
||||
task3.cpp
|
||||
@@ -0,0 +1,16 @@
|
||||
## source: https://docs.github.com/en/get-started/getting-started-with-git/configuring-git-to-handle-line-endings
|
||||
|
||||
# Set the default behavior, in case people don't have core.autocrlf set.
|
||||
* text=auto
|
||||
|
||||
# Explicitly declare text files you want to always be normalized and converted
|
||||
# to native line endings on checkout.
|
||||
*.h text
|
||||
*.hpp text
|
||||
*.c text
|
||||
*.cpp text
|
||||
*.py text
|
||||
*.ipynb text
|
||||
*.md text
|
||||
*.txt text
|
||||
*.csv text
|
||||
@@ -0,0 +1,360 @@
|
||||
# custom
|
||||
|
||||
*.csv
|
||||
*.png
|
||||
build
|
||||
doc
|
||||
.cache
|
||||
.vscode
|
||||
.idea
|
||||
|
||||
# https://github.com/github/gitignore/blob/main/CMake.gitignore
|
||||
|
||||
CMakeLists.txt.user
|
||||
CMakeCache.txt
|
||||
CMakeFiles
|
||||
CMakeScripts
|
||||
Testing
|
||||
Makefile
|
||||
cmake_install.cmake
|
||||
install_manifest.txt
|
||||
compile_commands.json
|
||||
CTestTestfile.cmake
|
||||
_deps
|
||||
|
||||
# ttps://github.com/github/gitignore/blob/main/C.gitignore
|
||||
|
||||
# Prerequisites
|
||||
*.d
|
||||
|
||||
# Object files
|
||||
*.o
|
||||
*.ko
|
||||
*.obj
|
||||
*.elf
|
||||
|
||||
# Linker output
|
||||
*.ilk
|
||||
*.map
|
||||
*.exp
|
||||
|
||||
# Precompiled Headers
|
||||
*.gch
|
||||
*.pch
|
||||
|
||||
# Libraries
|
||||
*.lib
|
||||
*.a
|
||||
*.la
|
||||
*.lo
|
||||
|
||||
# Shared objects (inc. Windows DLLs)
|
||||
*.dll
|
||||
*.so
|
||||
*.so.*
|
||||
*.dylib
|
||||
|
||||
# Executables
|
||||
*.exe
|
||||
*.out
|
||||
*.app
|
||||
*.i*86
|
||||
*.x86_64
|
||||
*.hex
|
||||
|
||||
# Debug files
|
||||
*.dSYM/
|
||||
*.su
|
||||
*.idb
|
||||
*.pdb
|
||||
|
||||
# Kernel Module Compile Results
|
||||
*.mod*
|
||||
*.cmd
|
||||
.tmp_versions/
|
||||
modules.order
|
||||
Module.symvers
|
||||
Mkfile.old
|
||||
dkms.conf
|
||||
|
||||
# https://github.com/github/gitignore/blob/main/C%2B%2B.gitignore
|
||||
|
||||
# Prerequisites
|
||||
*.d
|
||||
|
||||
# Compiled Object files
|
||||
*.slo
|
||||
*.lo
|
||||
*.o
|
||||
*.obj
|
||||
|
||||
# Precompiled Headers
|
||||
*.gch
|
||||
*.pch
|
||||
|
||||
# Compiled Dynamic libraries
|
||||
*.so
|
||||
*.dylib
|
||||
*.dll
|
||||
|
||||
# Fortran module files
|
||||
*.mod
|
||||
*.smod
|
||||
|
||||
# Compiled Static libraries
|
||||
*.lai
|
||||
*.la
|
||||
*.a
|
||||
*.lib
|
||||
|
||||
# Executables
|
||||
*.exe
|
||||
*.out
|
||||
*.app
|
||||
|
||||
# source: https://github.com/github/gitignore/blob/main/Python.gitignore
|
||||
|
||||
# Byte-compiled / optimized / DLL files
|
||||
__pycache__/
|
||||
*.py[cod]
|
||||
*$py.class
|
||||
|
||||
# C extensions
|
||||
*.so
|
||||
|
||||
# Distribution / packaging
|
||||
.Python
|
||||
build/
|
||||
develop-eggs/
|
||||
dist/
|
||||
downloads/
|
||||
eggs/
|
||||
.eggs/
|
||||
lib/
|
||||
lib64/
|
||||
parts/
|
||||
sdist/
|
||||
var/
|
||||
wheels/
|
||||
share/python-wheels/
|
||||
*.egg-info/
|
||||
.installed.cfg
|
||||
*.egg
|
||||
MANIFEST
|
||||
|
||||
# PyInstaller
|
||||
# Usually these files are written by a python script from a template
|
||||
# before PyInstaller builds the exe, so as to inject date/other infos into it.
|
||||
*.manifest
|
||||
*.spec
|
||||
|
||||
# Installer logs
|
||||
pip-log.txt
|
||||
pip-delete-this-directory.txt
|
||||
|
||||
# Unit test / coverage reports
|
||||
htmlcov/
|
||||
.tox/
|
||||
.nox/
|
||||
.coverage
|
||||
.coverage.*
|
||||
.cache
|
||||
nosetests.xml
|
||||
coverage.xml
|
||||
*.cover
|
||||
*.py,cover
|
||||
.hypothesis/
|
||||
.pytest_cache/
|
||||
cover/
|
||||
|
||||
# Translations
|
||||
*.mo
|
||||
*.pot
|
||||
|
||||
# Django stuff:
|
||||
*.log
|
||||
local_settings.py
|
||||
db.sqlite3
|
||||
db.sqlite3-journal
|
||||
|
||||
# Flask stuff:
|
||||
instance/
|
||||
.webassets-cache
|
||||
|
||||
# Scrapy stuff:
|
||||
.scrapy
|
||||
|
||||
# Sphinx documentation
|
||||
docs/_build/
|
||||
|
||||
# PyBuilder
|
||||
.pybuilder/
|
||||
target/
|
||||
|
||||
# Jupyter Notebook
|
||||
.ipynb_checkpoints
|
||||
|
||||
# IPython
|
||||
profile_default/
|
||||
ipython_config.py
|
||||
|
||||
# pyenv
|
||||
# For a library or package, you might want to ignore these files since the code is
|
||||
# intended to run in multiple environments; otherwise, check them in:
|
||||
# .python-version
|
||||
|
||||
# pipenv
|
||||
# According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.
|
||||
# However, in case of collaboration, if having platform-specific dependencies or dependencies
|
||||
# having no cross-platform support, pipenv may install dependencies that don't work, or not
|
||||
# install all needed dependencies.
|
||||
#Pipfile.lock
|
||||
|
||||
# poetry
|
||||
# Similar to Pipfile.lock, it is generally recommended to include poetry.lock in version control.
|
||||
# This is especially recommended for binary packages to ensure reproducibility, and is more
|
||||
# commonly ignored for libraries.
|
||||
# https://python-poetry.org/docs/basic-usage/#commit-your-poetrylock-file-to-version-control
|
||||
#poetry.lock
|
||||
|
||||
# pdm
|
||||
# Similar to Pipfile.lock, it is generally recommended to include pdm.lock in version control.
|
||||
#pdm.lock
|
||||
# pdm stores project-wide configurations in .pdm.toml, but it is recommended to not include it
|
||||
# in version control.
|
||||
# https://pdm.fming.dev/#use-with-ide
|
||||
.pdm.toml
|
||||
|
||||
# PEP 582; used by e.g. github.com/David-OConnor/pyflow and github.com/pdm-project/pdm
|
||||
__pypackages__/
|
||||
|
||||
# Celery stuff
|
||||
celerybeat-schedule
|
||||
celerybeat.pid
|
||||
|
||||
# SageMath parsed files
|
||||
*.sage.py
|
||||
|
||||
# Environments
|
||||
.env
|
||||
.venv
|
||||
env/
|
||||
venv/
|
||||
ENV/
|
||||
env.bak/
|
||||
venv.bak/
|
||||
|
||||
# Spyder project settings
|
||||
.spyderproject
|
||||
.spyproject
|
||||
|
||||
# Rope project settings
|
||||
.ropeproject
|
||||
|
||||
# mkdocs documentation
|
||||
/site
|
||||
|
||||
# mypy
|
||||
.mypy_cache/
|
||||
.dmypy.json
|
||||
dmypy.json
|
||||
|
||||
# Pyre type checker
|
||||
.pyre/
|
||||
|
||||
# pytype static type analyzer
|
||||
.pytype/
|
||||
|
||||
# Cython debug symbols
|
||||
cython_debug/
|
||||
|
||||
# jetbrain IDEs: https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore
|
||||
|
||||
# User-specific stuff
|
||||
.idea/**/workspace.xml
|
||||
.idea/**/tasks.xml
|
||||
.idea/**/usage.statistics.xml
|
||||
.idea/**/dictionaries
|
||||
.idea/**/shelf
|
||||
|
||||
# AWS User-specific
|
||||
.idea/**/aws.xml
|
||||
|
||||
# Generated files
|
||||
.idea/**/contentModel.xml
|
||||
|
||||
# Sensitive or high-churn files
|
||||
.idea/**/dataSources/
|
||||
.idea/**/dataSources.ids
|
||||
.idea/**/dataSources.local.xml
|
||||
.idea/**/sqlDataSources.xml
|
||||
.idea/**/dynamic.xml
|
||||
.idea/**/uiDesigner.xml
|
||||
.idea/**/dbnavigator.xml
|
||||
|
||||
# Gradle
|
||||
.idea/**/gradle.xml
|
||||
.idea/**/libraries
|
||||
|
||||
# Gradle and Maven with auto-import
|
||||
# When using Gradle or Maven with auto-import, you should exclude module files,
|
||||
# since they will be recreated, and may cause churn. Uncomment if using
|
||||
# auto-import.
|
||||
# .idea/artifacts
|
||||
# .idea/compiler.xml
|
||||
# .idea/jarRepositories.xml
|
||||
# .idea/modules.xml
|
||||
# .idea/*.iml
|
||||
# .idea/modules
|
||||
# *.iml
|
||||
# *.ipr
|
||||
|
||||
# CMake
|
||||
cmake-build-*/
|
||||
|
||||
# Mongo Explorer plugin
|
||||
.idea/**/mongoSettings.xml
|
||||
|
||||
# File-based project format
|
||||
*.iws
|
||||
|
||||
# IntelliJ
|
||||
out/
|
||||
|
||||
# mpeltonen/sbt-idea plugin
|
||||
.idea_modules/
|
||||
|
||||
# JIRA plugin
|
||||
atlassian-ide-plugin.xml
|
||||
|
||||
# Cursive Clojure plugin
|
||||
.idea/replstate.xml
|
||||
|
||||
# SonarLint plugin
|
||||
.idea/sonarlint/
|
||||
|
||||
# Crashlytics plugin (for Android Studio and IntelliJ)
|
||||
com_crashlytics_export_strings.xml
|
||||
crashlytics.properties
|
||||
crashlytics-build.properties
|
||||
fabric.properties
|
||||
|
||||
# Editor-based Rest Client
|
||||
.idea/httpRequests
|
||||
|
||||
# Android studio 3.1+ serialized cache file
|
||||
.idea/caches/build_file_checksums.ser
|
||||
|
||||
# VSCODE source: https://github.com/github/gitignore/blob/main/Global/VisualStudioCode.gitignore
|
||||
.vscode/*
|
||||
!.vscode/settings.json
|
||||
!.vscode/tasks.json
|
||||
!.vscode/launch.json
|
||||
!.vscode/extensions.json
|
||||
!.vscode/*.code-snippets
|
||||
|
||||
# Local History for Visual Studio Code
|
||||
.history/
|
||||
|
||||
# Built Visual Studio Code Extensions
|
||||
*.vsix
|
||||
@@ -0,0 +1,47 @@
|
||||
cmake_minimum_required(VERSION 3.20)
|
||||
|
||||
# define project metadata
|
||||
|
||||
project(exercise6 LANGUAGES CXX
|
||||
DESCRIPTION "exercise6"
|
||||
HOMEPAGE_URL "https://sgit.iue.tuwien.ac.at/360050/exercise6")
|
||||
|
||||
# setting required language standards
|
||||
|
||||
set(CMAKE_CXX_STANDARD 20)
|
||||
set(CMAKE_CXX_STANDARD_REQUIRED True)
|
||||
set(CMAKE_CXX_EXTENSIONS OFF)
|
||||
|
||||
# misc settings
|
||||
|
||||
# avoid ctest dashboard targets
|
||||
set_property(GLOBAL PROPERTY CTEST_TARGETS_ADDED 1)
|
||||
# generate a compile_commands.json
|
||||
set(CMAKE_EXPORT_COMPILE_COMMANDS ON)
|
||||
# make all symbols visible on windows (which is default on unix)
|
||||
set(CMAKE_WINDOWS_EXPORT_ALL_SYMBOLS ON)
|
||||
|
||||
# options
|
||||
|
||||
option(BUILD_TESTING "enable testing with ctest" ON)
|
||||
|
||||
# testing
|
||||
|
||||
include(CTest)
|
||||
|
||||
# get/setup dependencies
|
||||
|
||||
include_directories(modules)
|
||||
|
||||
# include own targets
|
||||
|
||||
add_executable(task1 task1.main.cpp)
|
||||
add_test(NAME task1 COMMAND task1 WORKING_DIRECTORY ${PROJECT_SOURCE_DIR})
|
||||
set_property(TEST task1 PROPERTY PASS_REGULAR_EXPRESSION "malloc.*3.*free")
|
||||
|
||||
add_executable(task2 task2.test.cpp)
|
||||
add_test(NAME task2 COMMAND task2 WORKING_DIRECTORY ${PROJECT_SOURCE_DIR})
|
||||
|
||||
add_executable(task3 task3.cpp task3.test.cpp)
|
||||
add_test(NAME task3 COMMAND task3 WORKING_DIRECTORY ${PROJECT_SOURCE_DIR})
|
||||
|
||||
@@ -0,0 +1,18 @@
|
||||
# Hausübung 6 (3 Punkte)
|
||||
|
||||
**Ausgabe**: Donnerstag 25. April 2024, vormittags.
|
||||
|
||||
**Abgabe bis**: Montag 6. Mai 2024, Ende des Tages.
|
||||
|
||||
**Abgabe via**: git-Repository mit dem Namen **`exercise6`** auf unserem git-Server https://sgit.iue.tuwien.ac.at
|
||||
|
||||
Details zum Abgabeprozess via `git` finden Sie hier: https://sgit.iue.tuwien.ac.at/360050/git
|
||||
|
||||
# Aufgabenstellung
|
||||
|
||||
In dieser Hausübung werden folgende Themen erstmalig einfliessen:
|
||||
|
||||
- Arbeiten mit Schnittstellenklassen (hier: *abstract base class*)
|
||||
- Dynamische Speicherallokation (`new`) und Freigabe (`delete`)
|
||||
|
||||
**Die genaue Beschreibung und Anforderungen finden Sie in [`main.ipynb`](main.ipynb) und im Quellcode.**
|
||||
@@ -0,0 +1 @@
|
||||
-Imodules
|
||||
@@ -0,0 +1,10 @@
|
||||
<svg xmlns='http://www.w3.org/2000/svg' version='1.1' preserveAspectRatio='xMidYMid meet' viewbox='-180 -200 400 400' width='400' height='400' >
|
||||
<g transform='matrix(1 0 0 -1 180 200)' >
|
||||
<line stroke-width='1' fill='none' stroke='black' x1='-50' y1='0' x2='50' y2='0' />
|
||||
<line stroke-width='1' fill='none' stroke='black' x1='0' y1='-50' x2='0' y2='50' />
|
||||
<line stroke-width='1' fill='none' stroke='black' x1='60' y1='0' x2='160' y2='0' />
|
||||
<line stroke-width='1' fill='none' stroke='black' x1='110' y1='-50' x2='110' y2='50' />
|
||||
<polyline stroke-width='1' fill='none' stroke='black' points=' -60,50 -90,30 -110,0 -90,-30 -60,-50 ' />
|
||||
<circle stroke-width='1' fill='none' stroke='black' r='200' cx='20' cy='0' />
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 738 B |
@@ -0,0 +1,228 @@
|
||||
{
|
||||
"cells": [
|
||||
{
|
||||
"attachments": {},
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Aufgabe 1: Ein eigenes kleines C++-Programm (*new*/*delete*/*abstract base class*) (1 Punkt)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"attachments": {},
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"Erstellen Sie in [`task1.main.cpp`](task1.main.cpp) ein lauffähiges Ein-Dateien-Programm das folgende Struktur aufweist:\n",
|
||||
"\n",
|
||||
"- Einbinden benötigter Header-Dateien aus der Standardbibliothek, z.B.:\n",
|
||||
"\t```cpp\n",
|
||||
"\t#include <iostream> // std::cout, std::endl\n",
|
||||
"\t#include <vector> // std::vector\n",
|
||||
"\t...\n",
|
||||
"\t```\n",
|
||||
"- Einbinden einer bestehenden Klassenhierarchie \n",
|
||||
"\t```cpp\n",
|
||||
"\t#include \"task1.hierarchy.hpp\"\n",
|
||||
"\t``` \n",
|
||||
"- Definition/Implementierung einer `main`-Funktion, die mit dynamische allozierte Instanzen der Klassen aus der Klassenhierarchie arbeitet , z.B.:\n",
|
||||
"\t```cpp\n",
|
||||
"\tint main(){\n",
|
||||
"\n",
|
||||
"\t auto ptr = new Circle(5);\t\t\n",
|
||||
"\t ...\n",
|
||||
"\n",
|
||||
"\t std::cout << ptr->area() << std::endl;\n",
|
||||
"\n",
|
||||
"\t delete ptr;\n",
|
||||
"\n",
|
||||
"\t return 0;\n",
|
||||
"\t}\n",
|
||||
"\t``` \n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"attachments": {},
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"- Eine genaue Beschreibung und Anforderungen finden Sie in [`task1.main.cpp`](task1.main.cpp)\n",
|
||||
"- Ihre Implementierung erfolgt ebenfalls in [`task1.main.cpp`](task1.main.cpp)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"attachments": {},
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Aufgabe 2: Erweitern einer gegebenen Klassenhierarchie (Implementierung weiterer abgeleiteter Klassen) (1 Punkt)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"attachments": {},
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"Es ist eine abstrakten Schnittstellenklasse für die Serialisierung eines XML-Elements `task2::Element` gegeben.\n",
|
||||
"Ebenso ist als Beispiel die Implementierung `task2::LineElement` gegeben, die diese Schnittstelle implementiert.\n",
|
||||
"\n",
|
||||
"Sie sollen zwei weitere Implementierung der Schnittstelle `task2::PolylineElement` und `task2::CircleElement` analog zu `task2::LineElement` implementieren.\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"attachments": {},
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"Implementieren Sie die folgende freie Funktionen:\n",
|
||||
"\n",
|
||||
"```cpp\n",
|
||||
"namespace task2 {\n",
|
||||
"\n",
|
||||
"struct Element {\n",
|
||||
" virtual std::string open() const = 0; ///< returns the opening or self-closing tag of an XML element\n",
|
||||
" virtual std::string text() const = 0; ///< returns the content tag of an XML element\n",
|
||||
" virtual std::string close() const = 0; ///< returns the closing tag of an XML element\n",
|
||||
"};\n",
|
||||
"\n",
|
||||
"struct LineElement : Element; // provided\n",
|
||||
"struct PolylineElement : Element; // todo\n",
|
||||
"struct CircleElement : Element; // todo\n",
|
||||
"\n",
|
||||
"```"
|
||||
]
|
||||
},
|
||||
{
|
||||
"attachments": {},
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"- Eine genaue Beschreibung der Schnittstellenklasse finden Sie in [`task2.Element.hpp`](task2.Element.hpp)\n",
|
||||
"- Das vorgegebene Beispiel finden Sie in [`task2.Line.hpp`](task2.Line.hpp)\n",
|
||||
"- Ihre Implementierung erfolgt in [`task2.Polyline.hpp`](task2.Polyline.hpp) und [`task2.Circle.hpp`](task2.Circle.hpp)\n",
|
||||
"- Die zugeordneten Tests finden Sie in [`task2.test.cpp`](task2.test.cpp)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"attachments": {},
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Aufgabe 3: Arbeiten mit einer gegebenen Klasse, die dynamisch allozierte Resourcen verwaltet, und an die dynamisch allozierte Resourcen übergeben werden (1 Punkt)\n",
|
||||
"\n",
|
||||
"Sie implementieren eine Funktion, die mittels ein SVG-Bild erzeugt und abspeichert:\n",
|
||||
"\n",
|
||||
"```cpp\n",
|
||||
"task2::BBox plot_image(std::filesystem::path filepath, \n",
|
||||
" const std::vector<task2::Line>& lines, \n",
|
||||
" const std::vector<task2::Polyline>& polylines,\n",
|
||||
" const std::vector<task2::Circle>& circles);\n",
|
||||
"```\n",
|
||||
"\n",
|
||||
"Zur Implementierung dieser kommt die Klasse `task3::Image` zum Einsatz. Die Schnittstellen dieser Klasse basieren auf `task2::Element`.\n",
|
||||
"\n",
|
||||
"```cpp\n",
|
||||
"namespace task3 {\n",
|
||||
"\n",
|
||||
"class Image {\n",
|
||||
"public:\n",
|
||||
" Image(Element* root) : root(root), elements() {}\n",
|
||||
" void add(Element* elem) { elements.push_back(elem); }\n",
|
||||
" void save(std::filesystem::path filepath) const;\n",
|
||||
" ~Image();\n",
|
||||
"private:\n",
|
||||
" Element* root; \n",
|
||||
" std::vector<Element*> elements;\n",
|
||||
"};\n",
|
||||
"\n",
|
||||
"}\n",
|
||||
"```"
|
||||
]
|
||||
},
|
||||
{
|
||||
"attachments": {},
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"- Die vorgegebenen Deklaration und eine genaue Beschreibung und Anforderungen finden Sie in [`task3.hpp`](task3.hpp)\n",
|
||||
"- Ihre Implementierung erfolgt in [`task3.cpp`](task3.cpp)\n",
|
||||
"- Die zugeordneten Tests finden Sie in [`task3.test.cpp`](task3.test.cpp)\n",
|
||||
"- In [`task3.Image.hpp`](task3.Image.hpp) finden Sie die vorgegebene Implementierung für `task3::Image`\n",
|
||||
"\n",
|
||||
"- Optional (für Interessierte): In [`task3.ImageUP.hpp`](task3.ImageUP.hpp) finden Sie eine alternative Implementierung `task3::ImageUP` die mit `std::unique_ptr` arbeitet.\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"attachments": {},
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"Unter Voraussetzung einer erfolgreicher Implementierung von Aufgabe 2 erzeugt der Test in Aufgabe 3 folgende Ausgabe:\n",
|
||||
"\n",
|
||||
""
|
||||
]
|
||||
},
|
||||
{
|
||||
"attachments": {},
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Kompilieren/Testen\n",
|
||||
"\n",
|
||||
"So testen Sie Ihre Implementierung (direkter Aufruf von `g++` und `python`):\n",
|
||||
"\n",
|
||||
"```shell\n",
|
||||
"# prepare\n",
|
||||
"mkdir build\n",
|
||||
"# compile\n",
|
||||
"g++ -g -std=c++20 task1.main.cpp -o build/task1\n",
|
||||
"g++ -g -Imodules -std=c++20 task2.test.cpp -o build/task2\n",
|
||||
"g++ -g -Imodules -std=c++20 task3.cpp task3.test.cpp -o build/task3\n",
|
||||
"\n",
|
||||
"# run tests\n",
|
||||
"./build/task1\n",
|
||||
"./build/task2\n",
|
||||
"./build/task3\n",
|
||||
"```\n",
|
||||
"\n",
|
||||
"Alternativ (mittels CMake-Configuration):s\n",
|
||||
"\n",
|
||||
"```shell\n",
|
||||
"# prepare\n",
|
||||
"cmake -S . -B build -D CMAKE_BUILD_TYPE=Debug\n",
|
||||
"# compile\n",
|
||||
"cmake --build build --config Debug --target task1\n",
|
||||
"cmake --build build --config Debug --target task2\n",
|
||||
"cmake --build build --config Debug --target task3\n",
|
||||
"cmake --build build --config Debug # all\n",
|
||||
"# run tests\n",
|
||||
"ctest --test-dir build -C Debug -R task1 \n",
|
||||
"ctest --test-dir build -C Debug -R task2 \n",
|
||||
"ctest --test-dir build -C Debug -R task3 \n",
|
||||
"ctest --test-dir build -C Debug # all\n",
|
||||
"``` \n"
|
||||
]
|
||||
}
|
||||
],
|
||||
"metadata": {
|
||||
"kernelspec": {
|
||||
"display_name": ".venv",
|
||||
"language": "python",
|
||||
"name": "python3"
|
||||
},
|
||||
"language_info": {
|
||||
"codemirror_mode": {
|
||||
"name": "ipython",
|
||||
"version": 3
|
||||
},
|
||||
"file_extension": ".py",
|
||||
"mimetype": "text/x-python",
|
||||
"name": "python",
|
||||
"nbconvert_exporter": "python",
|
||||
"pygments_lexer": "ipython3",
|
||||
"version": "3.6.15"
|
||||
}
|
||||
},
|
||||
"nbformat": 4,
|
||||
"nbformat_minor": 2
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
/// @file
|
||||
/// @brief Task1: simple hierarchy to be used in task1.main.cpp
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <numbers> // std::numbers::pi
|
||||
|
||||
namespace task1 {
|
||||
|
||||
struct Interface {
|
||||
double virtual area() const = 0;
|
||||
virtual ~Interface() {}
|
||||
};
|
||||
|
||||
struct Circle : Interface {
|
||||
Circle(double radius) : radius(radius) {}
|
||||
double radius;
|
||||
double virtual area() const final override { return std::numbers::pi * radius * radius; }
|
||||
};
|
||||
|
||||
struct Square : Interface {
|
||||
Square(double length) : length(length) {}
|
||||
double length;
|
||||
double virtual area() const final override { return length * length; }
|
||||
};
|
||||
|
||||
} // namespace task1
|
||||
@@ -0,0 +1,57 @@
|
||||
/// @file
|
||||
/// @brief Task1: "single-file" excutable C++ program
|
||||
|
||||
#include "task1.hierarchy.hpp" // task1::Interface, task1::Circle, task1::Rectangle
|
||||
#include <iostream>
|
||||
#include <vector> // for std::vector
|
||||
|
||||
/// @todo Include standard library headers as needed
|
||||
|
||||
/// @todo Implement a main funtion conducting the following tasks in this order:
|
||||
/// - create an empty vector of base pointers 'std::vector<task1::Interface *>'
|
||||
/// - dynamically allocate 5 Circles with radii set to 1,2,3,4, and 5
|
||||
/// - push the pointers to the dynamically allocated circles into the vector
|
||||
/// - dynamically allocate 5 Squares with length set to 1,2,3,4, and 5
|
||||
/// - push the pointers to the dynamically allocated squares into the vector
|
||||
/// - use a loop to iterate over the vector and count how many elements have an area less than 8.0
|
||||
/// - print the result to the console
|
||||
/// - use a loop to deallocate all 10 elements in the vector
|
||||
|
||||
/// @file
|
||||
/// @brief Task1: "single-file" excutable C++ program
|
||||
|
||||
/// @todo Implement a main funtion conducting the following tasks in this order:
|
||||
int main() {
|
||||
// Create an empty vector of base pointers
|
||||
std::vector<task1::Interface*> shapes;
|
||||
|
||||
// Dynamically allocate 5 Circles
|
||||
for (int i = 1; i <= 5; ++i) {
|
||||
shapes.push_back(new task1::Circle(i));
|
||||
std::cout << "malloc - Circle with radius " << i << std::endl;
|
||||
}
|
||||
|
||||
// Dynamically allocate 5 Squares
|
||||
for (int i = 1; i <= 5; ++i) {
|
||||
shapes.push_back(new task1::Square(i));
|
||||
std::cout << "malloc - Square with length " << i << std::endl;
|
||||
}
|
||||
|
||||
// Count elements with area less than 8.0
|
||||
int count = 0;
|
||||
for (auto* shape : shapes) {
|
||||
if (shape->area() < 8.0) {
|
||||
count++;
|
||||
}
|
||||
}
|
||||
std::cout << "Number of shapes with area less than 8.0: " << count << std::endl;
|
||||
|
||||
// Deallocate all elements in the vector
|
||||
for (auto* shape : shapes) {
|
||||
delete shape;
|
||||
std::cout << "free - Shape" << std::endl;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,43 @@
|
||||
/// @file
|
||||
/// @brief Task2: SVG-Circle element https://developer.mozilla.org/en-US/docs/Web/SVG/Element/circle
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "task2.Element.hpp"
|
||||
#include "task2.aliases.hpp"
|
||||
|
||||
/// @todo Include standard library headers as needed
|
||||
#include <sstream>
|
||||
#include <string>
|
||||
|
||||
namespace task2 {
|
||||
|
||||
/// @brief Circle SVG Element
|
||||
struct CircleElement : Element {
|
||||
Circle circle; // Now uses the alias Circle = std::tuple<Vec2i, int>
|
||||
|
||||
CircleElement(Circle circle) : circle(circle) {}
|
||||
|
||||
std::string open() const override final {
|
||||
std::stringstream ss;
|
||||
ss << "<circle ";
|
||||
ss << "cx='" << std::get<0>(circle)[0] << "' ";
|
||||
ss << "cy='" << std::get<0>(circle)[1] << "' ";
|
||||
ss << "r='" << std::get<1>(circle) << "' ";
|
||||
ss << "fill='none' ";
|
||||
ss << "stroke='black' ";
|
||||
ss << "stroke-width='1' ";
|
||||
ss << "/>";
|
||||
return ss.str();
|
||||
}
|
||||
|
||||
std::string text() const override final {
|
||||
return std::string();
|
||||
}
|
||||
|
||||
std::string close() const override final {
|
||||
return std::string();
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace task2
|
||||
@@ -0,0 +1,25 @@
|
||||
/// @file
|
||||
/// @brief Task2: Abstract base class used as interface to implement serialization of XML elements
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <string> // std::string
|
||||
|
||||
namespace task2 {
|
||||
|
||||
///@brief XML element interface
|
||||
struct Element {
|
||||
|
||||
virtual std::string open() const = 0; ///< returns the opening or self-closing tag of an XML element
|
||||
virtual std::string text() const = 0; ///< returns the content tag of an XML element
|
||||
virtual std::string close() const = 0; ///< returns the closing tag of an XML element
|
||||
|
||||
virtual ~Element() = default; ///< enable deletion of derived object instances via a base pointer
|
||||
|
||||
protected: ///< only accessible form within a derived class
|
||||
Element() = default; ///< default constructor
|
||||
Element(const Element&) = default; ///< copy constructor
|
||||
Element& operator=(const Element&) = default; ///< copy assignment
|
||||
};
|
||||
|
||||
} // namespace task2
|
||||
@@ -0,0 +1,42 @@
|
||||
/// @file
|
||||
/// @brief Task2: SVG-Line element https://developer.mozilla.org/en-US/docs/Web/SVG/Element/line
|
||||
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "task2.Element.hpp"
|
||||
#include "task2.aliases.hpp"
|
||||
|
||||
#include <sstream>
|
||||
#include <string>
|
||||
|
||||
namespace task2 {
|
||||
|
||||
/// @brief Line SVG Element
|
||||
/// open: <line fill='none' stroke='black' stroke-width='1' x1='{{a[0]}}' y1='{{a[1]}}' x2='{{b[0]}}' y2='{{b[1]}}' '/>
|
||||
/// text: empty string
|
||||
/// close: empty string
|
||||
struct LineElement : Element {
|
||||
LineElement(Line line) : line(line) { }
|
||||
std::string open() const override final {
|
||||
auto [a, b] = line;
|
||||
std::stringstream ss;
|
||||
ss << "<line ";
|
||||
ss << "stroke-width='1' ";
|
||||
ss << "fill='none' ";
|
||||
ss << "stroke='black' ";
|
||||
ss << "x1='" << a[0] << "' ";
|
||||
ss << "y1='" << a[1] << "' ";
|
||||
ss << "x2='" << b[0] << "' ";
|
||||
ss << "y2='" << b[1] << "' ";
|
||||
ss << " />";
|
||||
return ss.str();
|
||||
}
|
||||
std::string close() const override final { return std::string(); }
|
||||
std::string text() const override final { return std::string(); }
|
||||
|
||||
private:
|
||||
Line line;
|
||||
};
|
||||
|
||||
} // namespace task2
|
||||
@@ -0,0 +1,48 @@
|
||||
/// @file
|
||||
/// @brief Task2: SVG-Polyline element https://developer.mozilla.org/en-US/docs/Web/SVG/Element/polyline
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "task2.Element.hpp"
|
||||
#include "task2.aliases.hpp"
|
||||
|
||||
/// @todo Include standard library headers as needed
|
||||
#include <string>
|
||||
|
||||
namespace task2 {
|
||||
|
||||
/// @brief Polyline SVG Element
|
||||
/// @todo Implement the constructor from a task2::Polyline
|
||||
/// @todo Implement the class to return the fowllowing strings on the interface functions:
|
||||
/// open: <polyline fill='none' stroke='black' stroke-width='1' points=' x1,y1 x2,y2, x3,y3 ... '/>
|
||||
/// text: empty string
|
||||
/// close: empty string
|
||||
/// @note You can use/add member variables to the class as you see fit
|
||||
struct PolylineElement : Element {
|
||||
Polyline polyline;
|
||||
|
||||
PolylineElement(Polyline polyline) {
|
||||
this->polyline = polyline;
|
||||
}
|
||||
std::string open() const override final {
|
||||
std::stringstream ss;
|
||||
ss << "<polyline ";
|
||||
ss << "stroke-width='1' ";
|
||||
ss << "fill='none' ";
|
||||
ss << "stroke='black' ";
|
||||
ss << "points='";
|
||||
for (auto& point : polyline) {
|
||||
ss << point[0] << "," << point[1] << " ";
|
||||
}
|
||||
ss << "' />";
|
||||
return ss.str();
|
||||
}
|
||||
std::string close() const override final {
|
||||
return std::string();
|
||||
}
|
||||
std::string text() const override final {
|
||||
return std::string();
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace task2
|
||||
@@ -0,0 +1,18 @@
|
||||
/// @file
|
||||
/// @brief Task2: Convenience aliases for short notations for two-dimensional integer coordinates
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <array> // std::array
|
||||
#include <tuple> // std::tuple
|
||||
#include <vector> // std::vector
|
||||
|
||||
namespace task2 {
|
||||
|
||||
using Vec2i = std::array<int, 2>; ///< two-dimensional integer coordinate
|
||||
using BBox = std::tuple<Vec2i, Vec2i>; ///< bounding box (bottom-left and top-right corner)
|
||||
using Circle = std::tuple<Vec2i, int>; ///< circle (center and radius)
|
||||
using Line = std::tuple<Vec2i, Vec2i>; ///< line (start and end point)
|
||||
using Polyline = std::vector<Vec2i>; ///< polyline (sequence of points)
|
||||
|
||||
} // namespace task2
|
||||
@@ -0,0 +1,69 @@
|
||||
/// @file
|
||||
/// @brief Task2: tests
|
||||
|
||||
#include "task2.Circle.hpp"
|
||||
#include "task2.Line.hpp"
|
||||
#include "task2.Polyline.hpp"
|
||||
#include "task2.aliases.hpp"
|
||||
|
||||
#include <cassert> // assert
|
||||
#include <iostream> // std::cout, sts::endl
|
||||
#include <string> // std::string
|
||||
|
||||
bool contains(const std::string& str, const std::string& pattern) { return str.find(pattern) != std::string::npos; }
|
||||
|
||||
bool check_defaults(const std::string& str) {
|
||||
if (!contains(str, "stroke-width='1'"))
|
||||
return false;
|
||||
if (!contains(str, "fill='none'"))
|
||||
return false;
|
||||
if (!contains(str, "stroke='black'"))
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
int main() {
|
||||
|
||||
{ // LineElement
|
||||
auto line = task2::Line{{0, 0}, {11, 12}};
|
||||
auto elem = task2::LineElement(line);
|
||||
auto openstr = elem.open();
|
||||
assert(check_defaults(openstr));
|
||||
assert(openstr.starts_with("<line"));
|
||||
assert(contains(openstr, "x1='0'"));
|
||||
assert(contains(openstr, "y1='0'"));
|
||||
assert(contains(openstr, "x2='11'"));
|
||||
assert(contains(openstr, "y2='12'"));
|
||||
assert(openstr.ends_with("/>"));
|
||||
assert(elem.text().empty() && elem.close().empty());
|
||||
}
|
||||
|
||||
{ // CircleElement
|
||||
auto circle = task2::Circle{{5, 6}, 5};
|
||||
auto elem = task2::CircleElement(circle);
|
||||
auto openstr = elem.open();
|
||||
assert(check_defaults(openstr));
|
||||
assert(openstr.starts_with("<circle"));
|
||||
assert(contains(openstr, "cx='5'"));
|
||||
assert(contains(openstr, "cy='6'"));
|
||||
assert(contains(openstr, "r='5'"));
|
||||
assert(openstr.ends_with("/>"));
|
||||
assert(elem.text().empty() && elem.close().empty());
|
||||
}
|
||||
|
||||
{ // PolylineElement
|
||||
auto polyline = task2::Polyline{{1, 2}, {3, 4}, {5, 6}};
|
||||
auto elem = task2::PolylineElement(polyline);
|
||||
auto openstr = elem.open();
|
||||
assert(check_defaults(openstr));
|
||||
assert(openstr.starts_with("<polyline"));
|
||||
assert(contains(openstr, "points="));
|
||||
assert(contains(openstr, "1,2 3,4 5,6"));
|
||||
assert(openstr.ends_with("/>"));
|
||||
assert(elem.text().empty() && elem.close().empty());
|
||||
}
|
||||
|
||||
std::cout << "task2.test.cpp: all asserts passed" << std::endl;
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,63 @@
|
||||
/// @file
|
||||
/// @brief Task3: Simple SVG-Writer
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "task2.Element.hpp" // task2::Element
|
||||
|
||||
#include <filesystem> // std::filesystem::path
|
||||
#include <fstream> // std::ofstream
|
||||
#include <ostream> // std::endl
|
||||
#include <vector> // std::vector
|
||||
|
||||
namespace task2 {
|
||||
|
||||
/// @brief Simple SVG-Writer using the task2::Element interface
|
||||
class Image {
|
||||
|
||||
public:
|
||||
/// @brief Constructs an Image from a root SVG element
|
||||
/// @param root Pointer to a dynamically allocated element
|
||||
/// - ownership of the dynamic resource (pointer) is transfered to the class instance
|
||||
Image(Element* root) : root(root), elements() {}
|
||||
/// @brief Adds a SVG element inside the root element
|
||||
/// @param elem Pointer to a dynamically allocated element
|
||||
/// - ownership of the dynamic resource (pointer) is transfered to the class instance
|
||||
void add(Element* elem) { elements.push_back(elem); }
|
||||
/// @brief Writes the Image to a file
|
||||
/// @param filepath Filename of the image to be written
|
||||
void save(std::filesystem::path filepath) const {
|
||||
|
||||
std::ofstream fs;
|
||||
fs.exceptions(std::ifstream::badbit);
|
||||
fs.open(filepath);
|
||||
|
||||
fs << root->open() << std::endl;
|
||||
if (!root->text().empty())
|
||||
fs << root->text() << std::endl;
|
||||
|
||||
for (const auto& e : elements) {
|
||||
fs << " " << e->open() << std::endl;
|
||||
if (!e->text().empty())
|
||||
fs << " " << e->text() << std::endl;
|
||||
if (!e->close().empty())
|
||||
fs << " " << e->close() << std::endl;
|
||||
}
|
||||
|
||||
if (!root->close().empty())
|
||||
fs << root->close() << std::endl;
|
||||
}
|
||||
/// @brief Destructor
|
||||
/// @note Deallocates all dynamic resources owned by this instance
|
||||
~Image() {
|
||||
for (auto& e : elements)
|
||||
delete e;
|
||||
delete root;
|
||||
}
|
||||
|
||||
private:
|
||||
Element* root; ///< root element containing all other elements
|
||||
std::vector<Element*> elements; ///< sequence of elements
|
||||
};
|
||||
|
||||
} // namespace task2
|
||||
@@ -0,0 +1,53 @@
|
||||
#pragma once
|
||||
|
||||
#include "task2.Element.hpp" // task2::Element
|
||||
|
||||
#include <filesystem> // std::filesystem::path
|
||||
#include <fstream> // std::ofstream
|
||||
#include <memory> // std::unique_ptr
|
||||
#include <ostream> // std::endl
|
||||
#include <utility> // std::move
|
||||
#include <vector> // std::vector
|
||||
|
||||
namespace task2 {
|
||||
|
||||
/// @brief Simple SVG-Writer using the task2::Element interface
|
||||
class Image {
|
||||
|
||||
public:
|
||||
/// @brief Constructs an Image from a root SVG element
|
||||
/// @param root Pointer to the root element
|
||||
Image(std::unique_ptr<Element> root) : root(std::move(root)), elements() {}
|
||||
/// @brief Adds a SVG element inside the root element
|
||||
/// @param elem Pointer to the element
|
||||
void add(std::unique_ptr<Element> elem) { elements.emplace_back(std::move(elem)); }
|
||||
/// @brief Writes the Image to a file
|
||||
/// @param filepath Filename of the image to be written
|
||||
void save(std::filesystem::path filepath) const {
|
||||
|
||||
std::ofstream fs;
|
||||
fs.exceptions(std::ifstream::badbit);
|
||||
fs.open(filepath);
|
||||
|
||||
fs << root->open() << std::endl;
|
||||
if (!root->text().empty())
|
||||
fs << root->text() << std::endl;
|
||||
|
||||
for (const auto& e : elements) {
|
||||
fs << " " << e->open() << std::endl;
|
||||
if (!e->text().empty())
|
||||
fs << " " << e->text() << std::endl;
|
||||
if (!e->close().empty())
|
||||
fs << " " << e->close() << std::endl;
|
||||
}
|
||||
|
||||
if (!root->close().empty())
|
||||
fs << root->close() << std::endl;
|
||||
}
|
||||
|
||||
private:
|
||||
std::unique_ptr<Element> root; ///< root element containing all other elements
|
||||
std::vector<std::unique_ptr<Element>> elements; ///< sequence of elements
|
||||
};
|
||||
|
||||
} // namespace task2
|
||||
@@ -0,0 +1,55 @@
|
||||
/// @file
|
||||
/// @brief Task2: SVG-Root element https://developer.mozilla.org/en-US/docs/Web/SVG/Element/svg
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "task2.Element.hpp" // task2::Element
|
||||
#include "task2.aliases.hpp" // task2::BBox
|
||||
|
||||
#include <sstream> // std::stringstream
|
||||
#include <ostream> // std::endl
|
||||
#include <string> // std::string
|
||||
|
||||
namespace task2 {
|
||||
|
||||
/// @brief Root SVG Element (combined a <svg> and a <g> element)
|
||||
/// @note The group element is used to enable a common transform function for all contained elements to enable a bottom-left origin
|
||||
/// (the svg-default is top-left)
|
||||
/// open: <svg preserveAspectRatio='xMidYMid meet' viewbox='0 0 {{w}} {{h}}' height='{{w}}' width='{{h}}'>
|
||||
/// <g transform='matrix(1 0 0 -1 {{-xmin}} {{ymax}})'>
|
||||
/// text: empty string
|
||||
/// close: </g>
|
||||
/// </svg>
|
||||
struct RootElement : Element {
|
||||
RootElement(BBox bbox) : bbox(bbox) {}
|
||||
std::string open() const override final {
|
||||
auto [min, max] = bbox;
|
||||
double xorg = min[0];
|
||||
double yorg = min[1];
|
||||
double w = max[0] - min[0];
|
||||
double h = max[1] - min[1];
|
||||
std::stringstream ss;
|
||||
ss << "<svg ";
|
||||
ss << "xmlns='http://www.w3.org/2000/svg' ";
|
||||
ss << "version='1.1' ";
|
||||
ss << "preserveAspectRatio='xMidYMid meet' ";
|
||||
ss << "viewbox='" << xorg << " " << yorg << " " << w << " " << h << "' ";
|
||||
ss << "width='" << w << "' ";
|
||||
ss << "height='" << h << "' ";
|
||||
ss << ">" << std::endl;
|
||||
ss << "<g transform='matrix(1 0 0 -1 " << -min[0] << " " << max[1] << ")' >";
|
||||
return ss.str();
|
||||
}
|
||||
std::string close() const override final {
|
||||
std::stringstream ss;
|
||||
ss << "</g>" << std::endl;
|
||||
ss << "</svg>";
|
||||
return ss.str();
|
||||
};
|
||||
std::string text() const override final { return std::string(); }
|
||||
|
||||
private:
|
||||
BBox bbox;
|
||||
};
|
||||
|
||||
} // namespace task2
|
||||
@@ -0,0 +1,33 @@
|
||||
|
||||
#include "task3.hpp"
|
||||
#include "task3.Image.hpp"
|
||||
#include "task3.Root.hpp"
|
||||
#include "task2.Line.hpp"
|
||||
#include "task2.Polyline.hpp"
|
||||
#include "task2.Circle.hpp"
|
||||
|
||||
namespace task3 {
|
||||
|
||||
|
||||
|
||||
using namespace task2;
|
||||
|
||||
BBox plot_image(std::filesystem::path filepath, const std::vector<task2::Line>& lines, const std::vector<task2::Polyline>& polylines,
|
||||
const std::vector<task2::Circle>& circles) {
|
||||
|
||||
// Initialize bounding box with a default value
|
||||
Vec2i min_point = {INT_MAX, INT_MAX};
|
||||
Vec2i max_point = {INT_MIN, INT_MIN};
|
||||
|
||||
// Iterate over all lines
|
||||
for (const auto& line : lines) {
|
||||
// Update bounding box
|
||||
auto [p1, p2] = line;
|
||||
min_point = min(min_point, line.bbox().min);
|
||||
max_point = max(max_point, line.bbox().max);
|
||||
}
|
||||
|
||||
return BBox{min_point, max_point};
|
||||
}
|
||||
|
||||
} // namespace task3
|
||||
@@ -0,0 +1,22 @@
|
||||
/// @file
|
||||
/// @brief Task3: declaration
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "task2.aliases.hpp" // task2::Line, task2::Polyline, task2::Circle
|
||||
|
||||
#include <filesystem> // std::filesystem::path
|
||||
#include <vector> // std::vector
|
||||
|
||||
namespace task3 {
|
||||
|
||||
/// @brief Plots an SVG Image containing lines, polylines and circles
|
||||
/// @param filepath Filename of the image to be written
|
||||
/// @param lines Sequence of lines to be plotted
|
||||
/// @param polylines Sequence of polylines to be plotted
|
||||
/// @param circles Sequence of circles to be plotted
|
||||
/// @return Smallest bounding box fully containing all plotted shapes (for circles the area is also considered as extend of the shape)
|
||||
task2::BBox plot_image(std::filesystem::path filepath, const std::vector<task2::Line>& lines, const std::vector<task2::Polyline>& polylines,
|
||||
const std::vector<task2::Circle>& circles);
|
||||
|
||||
} // namespace task3
|
||||
@@ -0,0 +1,45 @@
|
||||
/// @file
|
||||
/// @brief Task3: tests
|
||||
|
||||
#include "task3.hpp"
|
||||
#include "task2.aliases.hpp"
|
||||
|
||||
#include <cassert> // assert
|
||||
#include <filesystem> // std::filesystem::exists
|
||||
#include <iostream> // std::cout, sts::endl
|
||||
#include <string> // std::string
|
||||
#include <thread> // std::this_thread::sleep_for, std::chrono_literals
|
||||
|
||||
int main() {
|
||||
|
||||
std::string filepath = "task3.test.svg";
|
||||
|
||||
auto hori1 = task2::Line{{-50, 0}, {50, 0}};
|
||||
auto vert1 = task2::Line{{0, -50}, {0, 50}};
|
||||
auto hori2 = task2::Line{{-50 + 110, 0}, {50 + 110, 0}};
|
||||
auto vert2 = task2::Line{{0 + 110, -50}, {0 + 110, 50}};
|
||||
std::vector<task2::Line> lines = {hori1, vert1, hori2, vert2};
|
||||
|
||||
auto cline = task2::Polyline{{-60, 50}, {-90, 30}, {-110, 0}, {-90, -30}, {-60, -50}};
|
||||
std::vector<task2::Polyline> polylines = {cline};
|
||||
|
||||
auto circle = task2::Circle{{20, 0}, 200};
|
||||
std::vector<task2::Circle> circles = {circle};
|
||||
|
||||
std::filesystem::remove(filepath);
|
||||
auto bbox = task3::plot_image(filepath, lines, polylines, circles);
|
||||
using namespace std::chrono_literals;
|
||||
std::this_thread::sleep_for(100ms);
|
||||
assert(std::filesystem::exists(filepath));
|
||||
|
||||
const auto& [bbmin, bbmax] = bbox;
|
||||
|
||||
assert(bbmin[0] == -180);
|
||||
assert(bbmax[0] == 220);
|
||||
assert(bbmin[1] == -200);
|
||||
assert(bbmax[1] == 200);
|
||||
|
||||
std::cout << "task3.test.cpp: all asserts passed" << std::endl;
|
||||
|
||||
return 0;
|
||||
}
|
||||
Reference in New Issue
Block a user