From 057b2d94e2417046c319870b86ca7668472b6132 Mon Sep 17 00:00:00 2001 From: ClemensLinnhoff Date: Tue, 22 Aug 2023 07:47:35 +0200 Subject: [PATCH 001/113] Add beam ID to LidarDetection Signed-off-by: ClemensLinnhoff --- osi_featuredata.proto | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/osi_featuredata.proto b/osi_featuredata.proto index 6cb30bee4..16ed85aaf 100644 --- a/osi_featuredata.proto +++ b/osi_featuredata.proto @@ -460,6 +460,10 @@ message LidarDetection // Unit: m/s // optional double radial_velocity = 12; + + // ID of the corresponding lidar beam. + // + optional Identifier beam_id = 13; } // From ef55b4d23ca9af6d471ad8867bde098a6a6e88cf Mon Sep 17 00:00:00 2001 From: Philip Windecker <95633467+philipwindecker@users.noreply.github.com> Date: Thu, 27 Jul 2023 10:55:18 +0200 Subject: [PATCH 002/113] Update release.yml Added Antora Generator call at the end to trigger the GitHub Pages build. Signed-off-by: Pierre R. Mai --- .github/workflows/release.yml | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 471651b6d..541186c34 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -182,3 +182,11 @@ jobs: with: file: ASAM_OSI_${{needs.setup.outputs.output1}}.zip tag: ${{ github.ref }} + - name: Trigger generator + if: ${{ env.MUP_KEY != '' }} + uses: peter-evans/repository-dispatch@v2 + with: + token: ${{ secrets.MACHINE_USER_PAT }} + event-type: antora-build-trigger + repository: OpenSimulationInterface/osi-antora-generator + client-payload: '{"src": "${{ github.repository }}", "ref": "master"}' From 2ed930ed7113c787b3acb1bc8a90cf05474e2d7d Mon Sep 17 00:00:00 2001 From: ClemensLinnhoff Date: Wed, 22 Nov 2023 09:44:13 +0100 Subject: [PATCH 003/113] Add osi_trafficcommandupdate.proto to CMakeLists Signed-off-by: ClemensLinnhoff --- CMakeLists.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/CMakeLists.txt b/CMakeLists.txt index dc99bbadb..2893279be 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -82,6 +82,7 @@ set(OSI_PROTO_FILES osi_trafficlight.proto osi_trafficupdate.proto osi_trafficcommand.proto + osi_trafficcommandupdate.proto osi_referenceline.proto osi_roadmarking.proto osi_lane.proto From 534daf581c5b00f892aaea8cf58997e37659212c Mon Sep 17 00:00:00 2001 From: "Pierre R. Mai" Date: Mon, 20 Nov 2023 11:39:30 +0100 Subject: [PATCH 004/113] Make CMAKE_CXX_STANDARD overridable (fix #741) Signed-off-by: Pierre R. Mai --- CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 2893279be..8c9626321 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -9,7 +9,7 @@ if(CMAKE_CURRENT_SOURCE_DIR STREQUAL CMAKE_SOURCE_DIR) endif() # Set the C++ standard -set(CMAKE_CXX_STANDARD 11) +set(CMAKE_CXX_STANDARD 11 CACHE STRING "C++ standard to be used") set(CMAKE_CXX_STANDARD_REQUIRED ON) # Optional Flatbuffer support From d00b974fee99355e001b49a63f42341b4b9f5dcc Mon Sep 17 00:00:00 2001 From: "Pierre R. Mai" Date: Thu, 11 Jan 2024 12:27:13 +0100 Subject: [PATCH 005/113] Add support for newer protobuf versions Signed-off-by: Pierre R. Mai --- .github/workflows/protobuf.yml | 79 ++++++++++++++++++++++------------ 1 file changed, 51 insertions(+), 28 deletions(-) diff --git a/.github/workflows/protobuf.yml b/.github/workflows/protobuf.yml index c719a68ce..b55078fb8 100644 --- a/.github/workflows/protobuf.yml +++ b/.github/workflows/protobuf.yml @@ -1,5 +1,10 @@ name: ProtoBuf CI Builds +env: + PROTOBUF_VERSION: 3.20.1 + PROTOBUF_VARIANT: '-all' # Use '-all' prior to 22.0, '' after + ABSEIL_VERSION: 20230802.1 + on: push: pull_request: @@ -13,14 +18,14 @@ jobs: steps: - name: Checkout OSI - uses: actions/checkout@v2 + uses: actions/checkout@v4 with: submodules: true - name: Setup Python - uses: actions/setup-python@v2 + uses: actions/setup-python@v5 with: - python-version: '3.7' + python-version: '3.8' - name: Install Python Dependencies run: python -m pip install --upgrade pip setuptools wheel pyyaml @@ -32,20 +37,29 @@ jobs: id: cache-depends uses: actions/cache@v3 with: - path: protobuf-3.20.1 + path: protobuf-${{ env.PROTOBUF_VERSION }} key: ${{ runner.os }}-v2-depends - - name: Download ProtoBuf + - name: Download ProtoBuf ${{ env.PROTOBUF_VERSION }} if: steps.cache-depends.outputs.cache-hit != 'true' - run: curl -OL https://github.com/protocolbuffers/protobuf/releases/download/v3.20.1/protobuf-all-3.20.1.tar.gz && tar xzvf protobuf-all-3.20.1.tar.gz + run: curl -OL https://github.com/protocolbuffers/protobuf/releases/download/v${{env.PROTOBUF_VERSION}}/protobuf${{env.PROTOBUF_VARIANT}}-${{env.PROTOBUF_VERSION}}.tar.gz && tar xzvf protobuf${{env.PROTOBUF_VARIANT}}-${{env.PROTOBUF_VERSION}}.tar.gz - - name: Build ProtoBuf - if: steps.cache-depends.outputs.cache-hit != 'true' - working-directory: protobuf-3.20.1 + - name: Download Abseil ${{ env.ABSEIL_VERSION }} + if: steps.cache-depends.outputs.cache-hit != 'true' && env.PROTOBUF_VARIANT == '' + run: curl -OL https://github.com/abseil/abseil-cpp/archive/refs/tags/${{env.ABSEIL_VERSION}}.tar.gz && tar xzvf ${{env.ABSEIL_VERSION}}.tar.gz && rm -rf protobuf-${{env.PROTOBUF_VERSION}}/third_party/abseil-cpp && mv abseil-cpp-${{env.ABSEIL_VERSION}} protobuf-${{env.PROTOBUF_VERSION}}/third_party/abseil-cpp + + - name: Build ProtoBuf ${{ env.PROTOBUF_VERSION }} via autotools + if: steps.cache-depends.outputs.cache-hit != 'true' && env.PROTOBUF_VARIANT == '-all' + working-directory: protobuf-${{ env.PROTOBUF_VERSION }} run: ./configure DIST_LANG=cpp --prefix=/usr && make - - name: Install ProtoBuf - working-directory: protobuf-3.20.1 + - name: Build ProtoBuf ${{ env.PROTOBUF_VERSION }} via cmake + if: steps.cache-depends.outputs.cache-hit != 'true' && env.PROTOBUF_VARIANT == '' + working-directory: protobuf-${{ env.PROTOBUF_VERSION }} + run: cmake -DCMAKE_CXX_STANDARD=17 -Dprotobuf_BUILD_SHARED_LIBS=ON -Dprotobuf_BUILD_TESTS=OFF . && cmake --build . --config Release -j 4 + + - name: Install ProtoBuf ${{ env.PROTOBUF_VERSION }} + working-directory: protobuf-${{ env.PROTOBUF_VERSION }} run: sudo make install && sudo ldconfig - name: Install proto2cpp @@ -57,17 +71,17 @@ jobs: # Versioning - name: Get versioning id: get_version - run: echo ::set-output name=VERSION::$(git describe --always) + run: echo "VERSION=$(git describe --always)" >> $GITHUB_OUTPUT - name: Prepare Documentation Build run: | sed -i 's/PROJECT_NUMBER\s*= @VERSION_MAJOR@.@VERSION_MINOR@.@VERSION_PATCH@/PROJECT_NUMBER = master (${{ steps.get_version.outputs.VERSION }})/g' doxygen_config.cmake.in - echo "EXCLUDE_PATTERNS = */osi3/* */protobuf-3.20.1/* */proto2cpp/* */flatbuffers/*" >> doxygen_config.cmake.in + echo "EXCLUDE_PATTERNS = */osi3/* */protobuf-*/* */proto2cpp/* */flatbuffers/*" >> doxygen_config.cmake.in echo "GENERATE_TREEVIEW = YES" >> doxygen_config.cmake.in - name: Configure C++ Build working-directory: build - run: cmake -D FILTER_PROTO2CPP_PY_PATH=$GITHUB_WORKSPACE/proto2cpp .. + run: cmake -D FILTER_PROTO2CPP_PY_PATH=$GITHUB_WORKSPACE/proto2cpp ${{ env.PROTOBUF_VARIANT =='' && '-DCMAKE_CXX_STANDARD=17' }} .. - name: Build C++ working-directory: build @@ -84,7 +98,7 @@ jobs: - name: Archive Documentation if: ${{ github.event_name == 'pull_request' }} - uses: actions/upload-artifact@v2 + uses: actions/upload-artifact@v4 with: name: linux64-doc path: doc/html @@ -104,36 +118,45 @@ jobs: steps: - name: Checkout OSI - uses: actions/checkout@v2 + uses: actions/checkout@v4 with: submodules: true - name: Setup Python - uses: actions/setup-python@v2 + uses: actions/setup-python@v5 with: - python-version: '3.7' + python-version: '3.8' - name: Install Python Dependencies run: python -m pip install --upgrade pip setuptools wheel pyyaml - name: Cache Dependencies id: cache-depends - uses: actions/cache@v2 + uses: actions/cache@v3 with: - path: protobuf-3.20.1 + path: protobuf-${{ env.PROTOBUF_VERSION }} key: ${{ runner.os }}-v2-depends - - name: Download ProtoBuf + - name: Download ProtoBuf ${{ env.PROTOBUF_VERSION }} if: steps.cache-depends.outputs.cache-hit != 'true' - run: curl -OL https://github.com/protocolbuffers/protobuf/releases/download/v3.20.1/protobuf-all-3.20.1.tar.gz && tar xzvf protobuf-all-3.20.1.tar.gz + run: curl -OL https://github.com/protocolbuffers/protobuf/releases/download/v${{env.PROTOBUF_VERSION}}/protobuf${{env.PROTOBUF_VARIANT}}-${{env.PROTOBUF_VERSION}}.tar.gz && tar xzvf protobuf${{env.PROTOBUF_VARIANT}}-${{env.PROTOBUF_VERSION}}.tar.gz - - name: Build ProtoBuf - if: steps.cache-depends.outputs.cache-hit != 'true' - working-directory: protobuf-3.20.1 + - name: Download Abseil ${{ env.ABSEIL_VERSION }} + if: steps.cache-depends.outputs.cache-hit != 'true' && env.PROTOBUF_VARIANT == '' + run: curl -OL https://github.com/abseil/abseil-cpp/archive/refs/tags/${{env.ABSEIL_VERSION}}.tar.gz && tar xzvf ${{env.ABSEIL_VERSION}}.tar.gz && rm -rf protobuf-${{env.PROTOBUF_VERSION}}/third_party/abseil-cpp && mv abseil-cpp-${{env.ABSEIL_VERSION}} protobuf-${{env.PROTOBUF_VERSION}}/third_party/abseil-cpp + + - name: Build ProtoBuf ${{ env.PROTOBUF_VERSION }} via autotools + if: steps.cache-depends.outputs.cache-hit != 'true' && env.PROTOBUF_VARIANT == '-all' + working-directory: protobuf-${{ env.PROTOBUF_VERSION }} run: ./configure DIST_LANG=cpp --prefix=/usr && make - - name: Install ProtoBuf - working-directory: protobuf-3.20.1 + - name: Build ProtoBuf ${{ env.PROTOBUF_VERSION }} via cmake + if: steps.cache-depends.outputs.cache-hit != 'true' && env.PROTOBUF_VARIANT == '' + working-directory: protobuf-${{ env.PROTOBUF_VERSION }} + run: cmake -DCMAKE_CXX_STANDARD=17 -Dprotobuf_BUILD_SHARED_LIBS=ON -Dprotobuf_BUILD_TESTS=OFF . && cmake --build . --config Release -j 4 + + - name: Install ProtoBuf ${{ env.PROTOBUF_VERSION }} + working-directory: protobuf-${{ env.PROTOBUF_VERSION }} run: sudo make install && sudo ldconfig - name: Prepare C++ Build @@ -146,7 +169,7 @@ jobs: - name: Configure C++ Build working-directory: build - run: cmake .. + run: cmake ${{ env.PROTOBUF_VARIANT =='' && '-DCMAKE_CXX_STANDARD=17' }} .. - name: Build C++ working-directory: build From a4fd54e84c471301d69c89b07e897cb8cc82bc74 Mon Sep 17 00:00:00 2001 From: Carlo van Driesten Date: Tue, 9 Jan 2024 15:36:38 +0100 Subject: [PATCH 006/113] Add .venv/ to .gitignore. Signed-off-by: Carlo van Driesten Signed-off-by: Pierre R. Mai --- .gitignore | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.gitignore b/.gitignore index 26cc62ce5..2076b7c5d 100644 --- a/.gitignore +++ b/.gitignore @@ -32,6 +32,8 @@ compile_commands.json # Python-generated files __pycache__/ +.venv/ +venv/ *.py[cod] proto2cpp.log .clang-format From ad258d91c1698750ca0c4f0aaa24647f1004eeb7 Mon Sep 17 00:00:00 2001 From: "Pierre R. Mai" Date: Fri, 12 Jan 2024 14:12:32 +0100 Subject: [PATCH 007/113] Move python dependencies to requirements_develop.txt Signed-off-by: Pierre R. Mai --- .github/workflows/protobuf.yml | 4 +++- requirements_develop.txt | 3 +++ setup.py | 1 + 3 files changed, 7 insertions(+), 1 deletion(-) create mode 100644 requirements_develop.txt diff --git a/.github/workflows/protobuf.yml b/.github/workflows/protobuf.yml index b55078fb8..feed38c13 100644 --- a/.github/workflows/protobuf.yml +++ b/.github/workflows/protobuf.yml @@ -28,7 +28,9 @@ jobs: python-version: '3.8' - name: Install Python Dependencies - run: python -m pip install --upgrade pip setuptools wheel pyyaml + run: | + python -m pip install --upgrade pip + python -m pip install -r requirements_develop.txt - name: Install Doxygen run: sudo apt-get install doxygen graphviz diff --git a/requirements_develop.txt b/requirements_develop.txt new file mode 100644 index 000000000..6548edd76 --- /dev/null +++ b/requirements_develop.txt @@ -0,0 +1,3 @@ +setuptools +wheel +pyyaml diff --git a/setup.py b/setup.py index 435207aeb..6dfbb7222 100644 --- a/setup.py +++ b/setup.py @@ -7,6 +7,7 @@ import re from distutils.spawn import find_executable +# setuptool is dependend on wheel package from setuptools import setup from setuptools.command.build_py import build_py From 493bd514055d7351e0264c84655489158d878b7b Mon Sep 17 00:00:00 2001 From: "Pierre R. Mai" Date: Fri, 12 Jan 2024 14:14:50 +0100 Subject: [PATCH 008/113] Apply black formatting and checking to python files Signed-off-by: Pierre R. Mai --- .github/workflows/protobuf.yml | 3 + format/OSITrace.py | 73 ++++++---- format/osi2read.py | 75 ++++++---- format/txt2osi.py | 83 ++++++----- requirements_develop.txt | 1 + setup.py | 140 +++++++++--------- tests/test_comment_type.py | 151 ++++++++++++++------ tests/test_doxygen_output.py | 35 +++-- tests/test_invalid_comment.py | 23 ++- tests/test_invalid_enum.py | 97 +++++++++---- tests/test_invalid_html.py | 134 +++++++++++------- tests/test_invalid_message.py | 227 ++++++++++++++++++++++-------- tests/test_invalid_punctuation.py | 11 +- tests/test_invalid_tabs.py | 9 +- tests/test_newline.py | 11 +- tests/test_non_ascii.py | 27 +++- tests/test_rules.py | 99 ++++++++++--- tests/test_units.py | 49 +++++-- 18 files changed, 852 insertions(+), 396 deletions(-) diff --git a/.github/workflows/protobuf.yml b/.github/workflows/protobuf.yml index feed38c13..da70a5db3 100644 --- a/.github/workflows/protobuf.yml +++ b/.github/workflows/protobuf.yml @@ -32,6 +32,9 @@ jobs: python -m pip install --upgrade pip python -m pip install -r requirements_develop.txt + - name: Check black format + run: black --check --diff . + - name: Install Doxygen run: sudo apt-get install doxygen graphviz diff --git a/format/OSITrace.py b/format/OSITrace.py index f6d3d39fe..d8d2c246a 100644 --- a/format/OSITrace.py +++ b/format/OSITrace.py @@ -10,9 +10,10 @@ from osi3.osi_groundtruth_pb2 import GroundTruth from osi3.osi_sensordata_pb2 import SensorData import warnings -warnings.simplefilter('default') -SEPARATOR = b'$$__$$' +warnings.simplefilter("default") + +SEPARATOR = b"$$__$$" SEPARATOR_LENGTH = len(SEPARATOR) BUFFER_SIZE = 1000000 @@ -31,7 +32,7 @@ def get_size_from_file_stream(file_object): MESSAGES_TYPE = { "SensorView": SensorView, "GroundTruth": GroundTruth, - "SensorData": SensorData + "SensorData": SensorData, } @@ -49,7 +50,7 @@ def __init__(self, path=None, type_name="SensorView"): def from_file(self, path, type_name="SensorView", max_index=-1, format_type=None): """Import a scenario from a file""" - if path.lower().endswith(('.lzma', '.xz')): + if path.lower().endswith((".lzma", ".xz")): self.scenario_file = lzma.open(path, "rb") else: self.scenario_file = open(path, "rb") @@ -57,7 +58,7 @@ def from_file(self, path, type_name="SensorView", max_index=-1, format_type=None self.type_name = type_name self.format_type = format_type - if self.format_type == 'separated': + if self.format_type == "separated": # warnings.warn("The separated trace files will be completely removed in the near future. Please convert them to *.osi files with the converter in the main OSI repository.", PendingDeprecationWarning) self.timestep_count = self.retrieve_message_offsets(max_index) else: @@ -73,7 +74,7 @@ def retrieve_message_offsets(self, max_index): scenario_size = get_size_from_file_stream(self.scenario_file) if max_index == -1: - max_index = float('inf') + max_index = float("inf") buffer_deque = deque(maxlen=2) @@ -100,7 +101,7 @@ def retrieve_message_offsets(self, max_index): self.scenario_file.seek(message_offset) while eof and found != -1: - buffer = buffer[found + SEPARATOR_LENGTH:] + buffer = buffer[found + SEPARATOR_LENGTH :] found = buffer.find(SEPARATOR) buffer_offset = scenario_size - len(buffer) @@ -126,7 +127,7 @@ def retrieve_message(self): self.message_offsets = [0] eof = False - # TODO Implement buffering for the scenarios + # TODO Implement buffering for the scenarios self.scenario_file.seek(0) serialized_message = self.scenario_file.read() INT_LENGTH = len(struct.pack(" 1000000000: # Throw a warning if trace file is bigger than 1GB - gb_size_input = round(message_length/1000000000, 2) - gb_size_output = round(3.307692308*message_length/1000000000, 2) - warnings.warn(f"The trace file you are trying to make readable has the size {gb_size_input}GB. This will generate a readable file with the size {gb_size_output}GB. Make sure you have enough disc space and memory to read the file with your text editor.", ResourceWarning) - - with open(name, 'a') as f: - + gb_size_input = round(message_length / 1000000000, 2) + gb_size_output = round(3.307692308 * message_length / 1000000000, 2) + warnings.warn( + f"The trace file you are trying to make readable has the size {gb_size_input}GB. This will generate a readable file with the size {gb_size_output}GB. Make sure you have enough disc space and memory to read the file with your text editor.", + ResourceWarning, + ) + + with open(name, "a") as f: if interval is None and index is None: for i in self.get_messages(): f.write(str(i)) - + if interval is not None and index is None: - if type(interval) == tuple and len(interval) == 2 and interval[0] 0: matchName = re.search(r"\b\w[\S]*\b\s*=", statement) if matchName is not None: - checkName = statement[matchName.start():matchName.end()-1] + checkName = statement[ + matchName.start() : matchName.end() - 1 + ] # Check field message type (remove field name) type = statement.replace(checkName, "") matchName = re.search(r"\b\w[\S\.]*\s*=", type) if matchName is not None: - checkType = " "+type[matchName.start():matchName.end()-1]+" " + checkType = ( + " " + + type[ + matchName.start() : matchName.end() - 1 + ] + + " " + ) # Test case 12: Check nested message type - matchNameConv = re.search(r"[ ][a-zA-Z][a-zA-Z0-9]*([\.][A-Z][a-zA-Z0-9]*)*[ ]",checkType) + matchNameConv = re.search( + r"[ ][a-zA-Z][a-zA-Z0-9]*([\.][A-Z][a-zA-Z0-9]*)*[ ]", + checkType, + ) # Search for a closing brace. matchClosingBrace = re.search("}", statement) if noMessage > 0 and matchClosingBrace is not None: noMessage -= 1 - # Test to check if '\\brief' is appended in comment section for short comments. if matchComment is not None: noComment += 1 @@ -210,16 +245,36 @@ def test_comment_existence(self): hasBrief = True elif len(saveStatement) == 0: - statement = statement.strip() - if re.search(r"\bmessage\b", statement) is not None or re.search(r"\bextend\b",statement) is not None or re.search(r"\benum\b", statement) is not None: - - self.assertNotEqual(noComment, 0, file + " in line " + str(i - 1) + ": comment is missing for: '" + statement + "'") + if ( + re.search(r"\bmessage\b", statement) is not None + or re.search(r"\bextend\b", statement) is not None + or re.search(r"\benum\b", statement) is not None + ): + self.assertNotEqual( + noComment, + 0, + file + + " in line " + + str(i - 1) + + ": comment is missing for: '" + + statement + + "'", + ) if noMessage > 0 or isEnum == True: if statement.find(";") != -1: - self.assertNotEqual(noComment, 0, file + " in line " + str(i) + ": comment is missing for: '" + statement + "'") + self.assertNotEqual( + noComment, + 0, + file + + " in line " + + str(i) + + ": comment is missing for: '" + + statement + + "'", + ) noComment = 0 hasBrief = False @@ -229,12 +284,20 @@ def test_comment_existence(self): if matchEnum is not None: isEnum = True - endOfLine = statement[matchEnum.end():] + endOfLine = statement[matchEnum.end() :] matchName = re.search(r"\b\w[\S]*\b", endOfLine) if matchName is not None: - # Test to ensure no special characters are in ENUM name. - matchNameConv = re.search(r"\b[A-Z][a-zA-Z0-9]*\b", endOfLine[matchName.start():matchName.end()]) - enumName = self.convert(endOfLine[matchName.start():matchName.end()]) + "_" + # Test to ensure no special characters are in ENUM name. + matchNameConv = re.search( + r"\b[A-Z][a-zA-Z0-9]*\b", + endOfLine[matchName.start() : matchName.end()], + ) + enumName = ( + self.convert( + endOfLine[matchName.start() : matchName.end()] + ) + + "_" + ) # Search for a closing brace. matchClosingBrace = re.search("}", statement) @@ -243,5 +306,5 @@ def test_comment_existence(self): enumName = "" def convert(self, name): - s1 = re.sub(r'(.)([A-Z][a-z]+)', r'\1_\2', name) - return re.sub(r'([a-z0-9])([A-Z])', r'\1_\2', s1).upper() \ No newline at end of file + s1 = re.sub(r"(.)([A-Z][a-z]+)", r"\1_\2", name) + return re.sub(r"([a-z0-9])([A-Z])", r"\1_\2", s1).upper() diff --git a/tests/test_doxygen_output.py b/tests/test_doxygen_output.py index 902e72ab8..37b80b4f4 100644 --- a/tests/test_doxygen_output.py +++ b/tests/test_doxygen_output.py @@ -4,29 +4,46 @@ DOC_FILES = glob.glob("doc/html/*.htm*") + class TestDoxygenOutput(unittest.TestCase): - """ Test class for the doxygen output. """ + """Test class for the doxygen output.""" def test_hash(self): - ''' Test case is checking if there are illegal hash chars in the documentation. -> doxygen link not found. ''' + """Test case is checking if there are illegal hash chars in the documentation. -> doxygen link not found.""" for file in DOC_FILES: with open(file, "rt") as fin, self.subTest(file=file): for i, line in enumerate(fin, start=1): - self.assertNotRegex(line, r"([\s>]|^)#\w(\S)*", file + " in line " + str(i) + ": not permitted hash found.") - + self.assertNotRegex( + line, + r"([\s>]|^)#\w(\S)*", + file + " in line " + str(i) + ": not permitted hash found.", + ) def test_slash_triplet(self): - ''' Test case is checking if there are slash triplets in the documentation. -> doxygen didn't interpret something properly. ''' + """Test case is checking if there are slash triplets in the documentation. -> doxygen didn't interpret something properly.""" for file in DOC_FILES: with open(file, "rt") as fin, self.subTest(file=file): for i, line in enumerate(fin, start=1): - self.assertNotRegex(line, r"([\s>]|^)///\s*", file + " in line " + str(i) + ": not permitted slash triplet found.") - + self.assertNotRegex( + line, + r"([\s>]|^)///\s*", + file + + " in line " + + str(i) + + ": not permitted slash triplet found.", + ) def test_backslash_triplet(self): - ''' Test case is checking if there are backslash triplets in the documentation. -> doxygen didn't interpret something properly. ''' + """Test case is checking if there are backslash triplets in the documentation. -> doxygen didn't interpret something properly.""" for file in DOC_FILES: with open(file, "rt") as fin, self.subTest(file=file): for i, line in enumerate(fin, start=1): - self.assertNotRegex(line, r"([\s>]|^)\\\\\\\s*", file + " in line " + str(i) + ": not permitted backslash triplet found.") + self.assertNotRegex( + line, + r"([\s>]|^)\\\\\\\s*", + file + + " in line " + + str(i) + + ": not permitted backslash triplet found.", + ) diff --git a/tests/test_invalid_comment.py b/tests/test_invalid_comment.py index 59c0f7163..39636e04b 100644 --- a/tests/test_invalid_comment.py +++ b/tests/test_invalid_comment.py @@ -3,20 +3,33 @@ PROTO_FILES = glob.glob("*.proto") + class TestInvalidCommentType(unittest.TestCase): """Test class for invalid comment types""" def test_triple_slash(self): - ''' Test to check if more than two forward slash('/') are present in comment section of proto file. ''' + """Test to check if more than two forward slash('/') are present in comment section of proto file.""" for file in PROTO_FILES: with open(file, "rt") as fin, self.subTest(file=file): for i, line in enumerate(fin, start=1): - self.assertEqual(line.find("///"), -1, file + " in line " + str(i) + ": not permitted use of '///' ") + self.assertEqual( + line.find("///"), + -1, + file + " in line " + str(i) + ": not permitted use of '///' ", + ) def test_comments_invalid_syntax(self): - ''' Test to check if comments are given using invalid syntax '/*' or '*/' ''' + """Test to check if comments are given using invalid syntax '/*' or '*/'""" for file in PROTO_FILES: with open(file, "rt") as fin, self.subTest(file=file): for i, line in enumerate(fin, start=1): - self.assertEqual(line.find("/*"), -1, file + " in line " + str(i) + ": not permitted use of '/*' ") - self.assertEqual(line.find("*/"), -1, file + " in line " + str(i) + ": not permitted use of '*/' ") \ No newline at end of file + self.assertEqual( + line.find("/*"), + -1, + file + " in line " + str(i) + ": not permitted use of '/*' ", + ) + self.assertEqual( + line.find("*/"), + -1, + file + " in line " + str(i) + ": not permitted use of '*/' ", + ) diff --git a/tests/test_invalid_enum.py b/tests/test_invalid_enum.py index 0ecee0b40..01d9ff9e9 100644 --- a/tests/test_invalid_enum.py +++ b/tests/test_invalid_enum.py @@ -4,11 +4,12 @@ PROTO_FILES = glob.glob("*.proto") + class TestInvalidEnum(unittest.TestCase): - ''' Test class to check invalid enum ''' + """Test class to check invalid enum""" def test_correct_enum_name(self): - ''' Test if enum name is correct. ''' + """Test if enum name is correct.""" for file in PROTO_FILES: with open(file, "rt") as fin, self.subTest(file=file): isEnum = False @@ -22,8 +23,8 @@ def test_correct_enum_name(self): matchComment = re.search("//", line) if matchComment is not None: - statement = line[:matchComment.start()] - comment = line[matchComment.end():] + statement = line[: matchComment.start()] + comment = line[matchComment.end() :] else: statement = line comment = "" @@ -42,8 +43,8 @@ def test_correct_enum_name(self): saveStatement = statement statement = "" else: - saveStatement = statement[matchSep.end():] - statement = statement[:matchSep.end()] + saveStatement = statement[matchSep.end() :] + statement = statement[: matchSep.end()] # This section will check PascalCase for enums and check enum name? @@ -51,26 +52,53 @@ def test_correct_enum_name(self): matchName = re.search(r"\b\w[\S:]+\b", statement) if matchName is not None: - checkName = statement[matchName.start():matchName.end()] + checkName = statement[matchName.start() : matchName.end()] # Test to check correct ENUM name. - self.assertEqual(checkName.find(enumName), 0, file + " in line " + str(i) + ": enum type wrong. '" + checkName + "' should start with '" + enumName + "'") + self.assertEqual( + checkName.find(enumName), + 0, + file + + " in line " + + str(i) + + ": enum type wrong. '" + + checkName + + "' should start with '" + + enumName + + "'", + ) # Test to check ENUM type is in captial letters/upper case. - self.assertEqual(checkName, checkName.upper(), file + " in line " + str(i) + ": enum type wrong. '" + checkName + "' should use upper case") - + self.assertEqual( + checkName, + checkName.upper(), + file + + " in line " + + str(i) + + ": enum type wrong. '" + + checkName + + "' should use upper case", + ) # Search for "enum". matchEnum = re.search(r"\benum\b", statement) if matchEnum is not None: isEnum = True - endOfLine = statement[matchEnum.end():] + endOfLine = statement[matchEnum.end() :] matchName = re.search(r"\b\w[\S]*\b", endOfLine) if matchName is not None: - # Test to ensure no special characters are in ENUM name. - matchNameConv = re.search(r"\b[A-Z][a-zA-Z0-9]*\b", endOfLine[matchName.start():matchName.end()]) - enumName = self.convert(endOfLine[matchName.start():matchName.end()]) + "_" + # Test to ensure no special characters are in ENUM name. + matchNameConv = re.search( + r"\b[A-Z][a-zA-Z0-9]*\b", + endOfLine[matchName.start() : matchName.end()], + ) + enumName = ( + self.convert( + endOfLine[matchName.start() : matchName.end()] + ) + + "_" + ) # Search for a closing brace. matchClosingBrace = re.search("}", statement) @@ -78,9 +106,8 @@ def test_correct_enum_name(self): isEnum = False enumName = "" - def test_invalid_enum(self): - ''' Test invalid enum definition. ''' + """Test invalid enum definition.""" for file in PROTO_FILES: with open(file, "rt") as fin, self.subTest(file=file): isEnum = False @@ -94,8 +121,8 @@ def test_invalid_enum(self): matchComment = re.search("//", line) if matchComment is not None: - statement = line[:matchComment.start()] - comment = line[matchComment.end():] + statement = line[: matchComment.start()] + comment = line[matchComment.end() :] else: statement = line comment = "" @@ -114,8 +141,8 @@ def test_invalid_enum(self): saveStatement = statement statement = "" else: - saveStatement = statement[matchSep.end():] - statement = statement[:matchSep.end()] + saveStatement = statement[matchSep.end() :] + statement = statement[: matchSep.end()] # This section will check PascalCase for enums and check enum name? @@ -123,20 +150,36 @@ def test_invalid_enum(self): matchName = re.search(r"\b\w[\S:]+\b", statement) if matchName is not None: - checkName = statement[matchName.start():matchName.end()] + checkName = statement[matchName.start() : matchName.end()] # Search for "enum". matchEnum = re.search(r"\benum\b", statement) if matchEnum is not None: isEnum = True - endOfLine = statement[matchEnum.end():] + endOfLine = statement[matchEnum.end() :] matchName = re.search(r"\b\w[\S]*\b", endOfLine) if matchName is not None: # Test to ensure no special characters are in ENUM name. - matchNameConv = re.search(r"\b[A-Z][a-zA-Z0-9]*\b", endOfLine[matchName.start():matchName.end()]) - self.assertIsNotNone(matchNameConv, file + " in line " + str(i) + ": enum name wrong. '" + endOfLine[matchName.start():matchName.end()] + "'") - enumName = self.convert(endOfLine[matchName.start():matchName.end()]) + "_" + matchNameConv = re.search( + r"\b[A-Z][a-zA-Z0-9]*\b", + endOfLine[matchName.start() : matchName.end()], + ) + self.assertIsNotNone( + matchNameConv, + file + + " in line " + + str(i) + + ": enum name wrong. '" + + endOfLine[matchName.start() : matchName.end()] + + "'", + ) + enumName = ( + self.convert( + endOfLine[matchName.start() : matchName.end()] + ) + + "_" + ) # Search for a closing brace. matchClosingBrace = re.search("}", statement) @@ -145,5 +188,5 @@ def test_invalid_enum(self): enumName = "" def convert(self, name): - s1 = re.sub(r'(.)([A-Z][a-z]+)', r'\1_\2', name) - return re.sub(r'([a-z0-9])([A-Z])', r'\1_\2', s1).upper() \ No newline at end of file + s1 = re.sub(r"(.)([A-Z][a-z]+)", r"\1_\2", name) + return re.sub(r"([a-z0-9])([A-Z])", r"\1_\2", s1).upper() diff --git a/tests/test_invalid_html.py b/tests/test_invalid_html.py index 776b0b5a3..037ccd9bb 100644 --- a/tests/test_invalid_html.py +++ b/tests/test_invalid_html.py @@ -4,11 +4,12 @@ PROTO_FILES = glob.glob("*.proto") + class TestInvalidHtml(unittest.TestCase): - """ Test class for invalid html comment. """ + """Test class for invalid html comment.""" def test_invalid_slash(self): - ''' Test case to check invalid slash in htmlonly sections ''' + """Test case to check invalid slash in htmlonly sections""" for file in PROTO_FILES: with open(file, "rt") as fin, self.subTest(file=file): htmlblock = False @@ -18,8 +19,8 @@ def test_invalid_slash(self): # Search for comment ("//"). matchComment = re.search("//", line) if matchComment is not None: - statement = line[:matchComment.start()] - comment = line[matchComment.end():] + statement = line[: matchComment.start()] + comment = line[matchComment.end() :] else: statement = line comment = "" @@ -38,8 +39,8 @@ def test_invalid_slash(self): saveStatement = statement statement = "" else: - saveStatement = statement[matchSep.end():] - statement = statement[:matchSep.end()] + saveStatement = statement[matchSep.end() :] + statement = statement[: matchSep.end()] # Test case is checking comment and html tags if matchComment is not None: @@ -48,9 +49,8 @@ def test_invalid_slash(self): if htmlblock is False: matchHTMLOnly = re.search(r"\\htmlonly", comment) if matchHTMLOnly is not None: - - htmlComment = comment[matchHTMLOnly.end():] - htmlFreeComment = comment[:matchHTMLOnly.start()] + htmlComment = comment[matchHTMLOnly.end() :] + htmlFreeComment = comment[: matchHTMLOnly.start()] htmlblock = True else: htmlComment = comment @@ -59,16 +59,27 @@ def test_invalid_slash(self): if htmlblock is True: matchEndHTMLOnly = re.search(r"\\endhtmlonly", htmlComment) if matchEndHTMLOnly is not None: - htmlFreeComment = htmlFreeComment + htmlComment[matchEndHTMLOnly.end():] - htmlComment = htmlComment[:matchEndHTMLOnly.start()] + htmlFreeComment = ( + htmlFreeComment + + htmlComment[matchEndHTMLOnly.end() :] + ) + htmlComment = htmlComment[: matchEndHTMLOnly.start()] htmlblock = False # Test case to check html tags only in htmlonly sections - self.assertEqual(htmlComment.find("\\"), -1, file + " in line " + str(i) + ": doxygen comment \\.. reference found: '" + htmlComment + "'") - + self.assertEqual( + htmlComment.find("\\"), + -1, + file + + " in line " + + str(i) + + ": doxygen comment \\.. reference found: '" + + htmlComment + + "'", + ) def test_invalid_hash(self): - ''' Test case to check invalid # in htmlonly sections ''' + """Test case to check invalid # in htmlonly sections""" for file in PROTO_FILES: with open(file, "rt") as fin, self.subTest(file=file): htmlblock = False @@ -78,8 +89,8 @@ def test_invalid_hash(self): # Search for comment ("//"). matchComment = re.search("//", line) if matchComment is not None: - statement = line[:matchComment.start()] - comment = line[matchComment.end():] + statement = line[: matchComment.start()] + comment = line[matchComment.end() :] else: statement = line comment = "" @@ -98,8 +109,8 @@ def test_invalid_hash(self): saveStatement = statement statement = "" else: - saveStatement = statement[matchSep.end():] - statement = statement[:matchSep.end()] + saveStatement = statement[matchSep.end() :] + statement = statement[: matchSep.end()] # Test case is checking comment and html tags if matchComment is not None: @@ -108,9 +119,8 @@ def test_invalid_hash(self): if htmlblock is False: matchHTMLOnly = re.search(r"\\htmlonly", comment) if matchHTMLOnly is not None: - - htmlComment = comment[matchHTMLOnly.end():] - htmlFreeComment = comment[:matchHTMLOnly.start()] + htmlComment = comment[matchHTMLOnly.end() :] + htmlFreeComment = comment[: matchHTMLOnly.start()] htmlblock = True else: htmlComment = comment @@ -119,15 +129,26 @@ def test_invalid_hash(self): if htmlblock is True: matchEndHTMLOnly = re.search(r"\\endhtmlonly", htmlComment) if matchEndHTMLOnly is not None: - htmlFreeComment = htmlFreeComment + htmlComment[matchEndHTMLOnly.end():] - htmlComment = htmlComment[:matchEndHTMLOnly.start()] + htmlFreeComment = ( + htmlFreeComment + + htmlComment[matchEndHTMLOnly.end() :] + ) + htmlComment = htmlComment[: matchEndHTMLOnly.start()] htmlblock = False - self.assertEqual(htmlComment.find("#"), -1, file + " in line " + str(i) + ": doxygen comment #.. reference found: '" + htmlComment + "'") - + self.assertEqual( + htmlComment.find("#"), + -1, + file + + " in line " + + str(i) + + ": doxygen comment #.. reference found: '" + + htmlComment + + "'", + ) def test_invalid_at(self): - ''' Test case to check invalid @ in comments ''' + """Test case to check invalid @ in comments""" for file in PROTO_FILES: with open(file, "rt") as fin, self.subTest(file=file): htmlblock = False @@ -137,8 +158,8 @@ def test_invalid_at(self): # Search for comment ("//"). matchComment = re.search("//", line) if matchComment is not None: - statement = line[:matchComment.start()] - comment = line[matchComment.end():] + statement = line[: matchComment.start()] + comment = line[matchComment.end() :] else: statement = line comment = "" @@ -157,8 +178,8 @@ def test_invalid_at(self): saveStatement = statement statement = "" else: - saveStatement = statement[matchSep.end():] - statement = statement[:matchSep.end()] + saveStatement = statement[matchSep.end() :] + statement = statement[: matchSep.end()] # Test case is checking comment and html tags if matchComment is not None: @@ -167,9 +188,8 @@ def test_invalid_at(self): if htmlblock is False: matchHTMLOnly = re.search(r"\\htmlonly", comment) if matchHTMLOnly is not None: - - htmlComment = comment[matchHTMLOnly.end():] - htmlFreeComment = comment[:matchHTMLOnly.start()] + htmlComment = comment[matchHTMLOnly.end() :] + htmlFreeComment = comment[: matchHTMLOnly.start()] htmlblock = True else: htmlComment = comment @@ -178,14 +198,26 @@ def test_invalid_at(self): if htmlblock is True: matchEndHTMLOnly = re.search(r"\\endhtmlonly", htmlComment) if matchEndHTMLOnly is not None: - htmlFreeComment = htmlFreeComment + htmlComment[matchEndHTMLOnly.end():] - htmlComment = htmlComment[:matchEndHTMLOnly.start()] + htmlFreeComment = ( + htmlFreeComment + + htmlComment[matchEndHTMLOnly.end() :] + ) + htmlComment = htmlComment[: matchEndHTMLOnly.start()] htmlblock = False - self.assertEqual(comment.find("@"), -1, file + " in line " + str(i) + ": @ tag found (please replace with \\): '" + htmlFreeComment + "'") + self.assertEqual( + comment.find("@"), + -1, + file + + " in line " + + str(i) + + ": @ tag found (please replace with \\): '" + + htmlFreeComment + + "'", + ) def test_no_endhtmlonly(self): - ''' Test case to check no \endhtmlonly in comments ''' + """Test case to check no \endhtmlonly in comments""" for file in PROTO_FILES: with open(file, "rt") as fin, self.subTest(file=file): htmlblock = False @@ -195,8 +227,8 @@ def test_no_endhtmlonly(self): # Search for comment ("//"). matchComment = re.search("//", line) if matchComment is not None: - statement = line[:matchComment.start()] - comment = line[matchComment.end():] + statement = line[: matchComment.start()] + comment = line[matchComment.end() :] else: statement = line comment = "" @@ -215,8 +247,8 @@ def test_no_endhtmlonly(self): saveStatement = statement statement = "" else: - saveStatement = statement[matchSep.end():] - statement = statement[:matchSep.end()] + saveStatement = statement[matchSep.end() :] + statement = statement[: matchSep.end()] # Test case is checking comment and html tags if matchComment is not None: @@ -225,9 +257,8 @@ def test_no_endhtmlonly(self): if htmlblock is False: matchHTMLOnly = re.search(r"\\htmlonly", comment) if matchHTMLOnly is not None: - - htmlComment = comment[matchHTMLOnly.end():] - htmlFreeComment = comment[:matchHTMLOnly.start()] + htmlComment = comment[matchHTMLOnly.end() :] + htmlFreeComment = comment[: matchHTMLOnly.start()] htmlblock = True else: htmlComment = comment @@ -237,10 +268,19 @@ def test_no_endhtmlonly(self): matchEndHTMLOnly = re.search(r"\\endhtmlonly", htmlComment) if matchEndHTMLOnly is not None: - htmlFreeComment = htmlFreeComment + htmlComment[matchEndHTMLOnly.end():] - htmlComment = htmlComment[:matchEndHTMLOnly.start()] + htmlFreeComment = ( + htmlFreeComment + + htmlComment[matchEndHTMLOnly.end() :] + ) + htmlComment = htmlComment[: matchEndHTMLOnly.start()] htmlblock = False elif htmlblock: - self.assertFalse(htmlblock, file + " in line " + str(i - 1) + ": doxygen comment html section without endhtmlonly") + self.assertFalse( + htmlblock, + file + + " in line " + + str(i - 1) + + ": doxygen comment html section without endhtmlonly", + ) htmlblock = False diff --git a/tests/test_invalid_message.py b/tests/test_invalid_message.py index 8d2f8eaf5..04eafc8a4 100644 --- a/tests/test_invalid_message.py +++ b/tests/test_invalid_message.py @@ -4,11 +4,12 @@ PROTO_FILES = glob.glob("*.proto") + class TestInvalidMessage(unittest.TestCase): - """ Test class for invalid html comment. """ + """Test class for invalid html comment.""" def test_message_name(self): - ''' Test to check if message name have any special character. It should not have any special character. ''' + """Test to check if message name have any special character. It should not have any special character.""" for file in PROTO_FILES: with open(file, "rt") as fin, self.subTest(file=file): @@ -26,8 +27,8 @@ def test_message_name(self): matchComment = re.search("//", line) if matchComment is not None: - statement = line[:matchComment.start()] - comment = line[matchComment.end():] + statement = line[: matchComment.start()] + comment = line[matchComment.end() :] else: statement = line comment = "" @@ -46,8 +47,8 @@ def test_message_name(self): saveStatement = statement statement = "" else: - saveStatement = statement[matchSep.end():] - statement = statement[:matchSep.end()] + saveStatement = statement[matchSep.end() :] + statement = statement[: matchSep.end()] if isEnum is False: # Check if not inside an enum. @@ -57,25 +58,44 @@ def test_message_name(self): if matchMessage is not None: # a new message or a new nested message noMessage += 1 - endOfLine = statement[matchMessage.end():] + endOfLine = statement[matchMessage.end() :] matchName = re.search(r"\b\w[\S]*\b", endOfLine) if matchName is not None: # Test to check if message name have any special character. It should not have any special character. # Message should always start with special character. - matchNameConv = re.search(r"\b[A-Z][a-zA-Z0-9]*\b",endOfLine[matchName.start():matchName.end()]) - self.assertIsNotNone(matchNameConv, file + " in line " + str(i - 1) + ": message name wrong. '" + endOfLine[matchName.start():matchName.end()] + "'") + matchNameConv = re.search( + r"\b[A-Z][a-zA-Z0-9]*\b", + endOfLine[matchName.start() : matchName.end()], + ) + self.assertIsNotNone( + matchNameConv, + file + + " in line " + + str(i - 1) + + ": message name wrong. '" + + endOfLine[matchName.start() : matchName.end()] + + "'", + ) # Search for "enum". matchEnum = re.search(r"\benum\b", statement) if matchEnum is not None: isEnum = True - endOfLine = statement[matchEnum.end():] + endOfLine = statement[matchEnum.end() :] matchName = re.search(r"\b\w[\S]*\b", endOfLine) if matchName is not None: # Test to check presence of invalid special characters - matchNameConv = re.search(r"\b[A-Z][a-zA-Z0-9]*\b", endOfLine[matchName.start():matchName.end()]) - enumName = self.convert(endOfLine[matchName.start():matchName.end()]) + "_" + matchNameConv = re.search( + r"\b[A-Z][a-zA-Z0-9]*\b", + endOfLine[matchName.start() : matchName.end()], + ) + enumName = ( + self.convert( + endOfLine[matchName.start() : matchName.end()] + ) + + "_" + ) # Search for a closing brace. matchClosingBrace = re.search("}", statement) @@ -83,9 +103,8 @@ def test_message_name(self): isEnum = False enumName = "" - def test_field_name(self): - ''' Test to check if field names are in lower case. ''' + """Test to check if field names are in lower case.""" for file in PROTO_FILES: with open(file, "rt") as fin, self.subTest(file=file): @@ -104,8 +123,8 @@ def test_field_name(self): matchComment = re.search("//", line) if matchComment is not None: - statement = line[:matchComment.start()] - comment = line[matchComment.end():] + statement = line[: matchComment.start()] + comment = line[matchComment.end() :] else: statement = line comment = "" @@ -124,8 +143,8 @@ def test_field_name(self): saveStatement = statement statement = "" else: - saveStatement = statement[matchSep.end():] - statement = statement[:matchSep.end()] + saveStatement = statement[matchSep.end() :] + statement = statement[: matchSep.end()] if isEnum is False: # Check if not inside an enum. @@ -135,10 +154,13 @@ def test_field_name(self): if matchMessage is not None: # a new message or a new nested message noMessage += 1 - endOfLine = statement[matchMessage.end():] + endOfLine = statement[matchMessage.end() :] matchName = re.search(r"\b\w[\S]*\b", endOfLine) if matchName is not None: - matchNameConv = re.search(r"\b[A-Z][a-zA-Z0-9]*\b",endOfLine[matchName.start():matchName.end()]) + matchNameConv = re.search( + r"\b[A-Z][a-zA-Z0-9]*\b", + endOfLine[matchName.start() : matchName.end()], + ) elif re.search(r"\bextend\b", statement) is not None: # treat extend as message @@ -149,15 +171,35 @@ def test_field_name(self): matchName = re.search(r"\b\w[\S]*\b\s*=", statement) if matchName is not None: - checkName = statement[matchName.start():matchName.end() - 1] - self.assertEqual(checkName, checkName.lower(), file + " in line " + str(i) + ": field name wrong. '" + checkName + "' should use lower case") + checkName = statement[ + matchName.start() : matchName.end() - 1 + ] + self.assertEqual( + checkName, + checkName.lower(), + file + + " in line " + + str(i) + + ": field name wrong. '" + + checkName + + "' should use lower case", + ) type = statement.replace(checkName, "") matchName = re.search(r"\b\w[\S\.]*\s*=", type) if matchName is not None: - checkType = " " + type[matchName.start():matchName.end() - 1] + " " + checkType = ( + " " + + type[ + matchName.start() : matchName.end() - 1 + ] + + " " + ) # Test to check nested message type - matchNameConv = re.search(r"[ ][a-zA-Z][a-zA-Z0-9]*([\.][A-Z][a-zA-Z0-9]*)*[ ]",checkType) + matchNameConv = re.search( + r"[ ][a-zA-Z][a-zA-Z0-9]*([\.][A-Z][a-zA-Z0-9]*)*[ ]", + checkType, + ) # Search for a closing brace. matchClosingBrace = re.search("}", statement) @@ -169,12 +211,20 @@ def test_field_name(self): if matchEnum is not None: isEnum = True - endOfLine = statement[matchEnum.end():] + endOfLine = statement[matchEnum.end() :] matchName = re.search(r"\b\w[\S]*\b", endOfLine) if matchName is not None: # Test to check presence of invalid special characters - matchNameConv = re.search(r"\b[A-Z][a-zA-Z0-9]*\b", endOfLine[matchName.start():matchName.end()]) - enumName = self.convert(endOfLine[matchName.start():matchName.end()]) + "_" + matchNameConv = re.search( + r"\b[A-Z][a-zA-Z0-9]*\b", + endOfLine[matchName.start() : matchName.end()], + ) + enumName = ( + self.convert( + endOfLine[matchName.start() : matchName.end()] + ) + + "_" + ) # Search for a closing brace. matchClosingBrace = re.search("}", statement) @@ -183,7 +233,7 @@ def test_field_name(self): enumName = "" def test_field_type(self): - ''' Test to check nested message type. ''' + """Test to check nested message type.""" for file in PROTO_FILES: with open(file, "rt") as fin, self.subTest(file=file): @@ -202,8 +252,8 @@ def test_field_type(self): matchComment = re.search("//", line) if matchComment is not None: - statement = line[:matchComment.start()] - comment = line[matchComment.end():] + statement = line[: matchComment.start()] + comment = line[matchComment.end() :] else: statement = line comment = "" @@ -222,8 +272,8 @@ def test_field_type(self): saveStatement = statement statement = "" else: - saveStatement = statement[matchSep.end():] - statement = statement[:matchSep.end()] + saveStatement = statement[matchSep.end() :] + statement = statement[: matchSep.end()] if isEnum is False: # Check if not inside an enum. @@ -233,10 +283,13 @@ def test_field_type(self): if matchMessage is not None: # a new message or a new nested message noMessage += 1 - endOfLine = statement[matchMessage.end():] + endOfLine = statement[matchMessage.end() :] matchName = re.search(r"\b\w[\S]*\b", endOfLine) if matchName is not None: - matchNameConv = re.search(r"\b[A-Z][a-zA-Z0-9]*\b",endOfLine[matchName.start():matchName.end()]) + matchNameConv = re.search( + r"\b[A-Z][a-zA-Z0-9]*\b", + endOfLine[matchName.start() : matchName.end()], + ) elif re.search(r"\bextend\b", statement) is not None: # treat extend as message @@ -246,18 +299,37 @@ def test_field_type(self): if noMessage > 0: matchName = re.search(r"\b\w[\S]*\b\s*=", statement) if matchName is not None: - checkName = statement[matchName.start():matchName.end() - 1] + checkName = statement[ + matchName.start() : matchName.end() - 1 + ] # Check field message type (remove field name) type = statement.replace(checkName, "") matchName = re.search(r"\b\w[\S\.]*\s*=", type) if matchName is not None: - checkType = " " + type[matchName.start():matchName.end() - 1] + " " + checkType = ( + " " + + type[ + matchName.start() : matchName.end() - 1 + ] + + " " + ) # Test to check nested message type - matchNameConv = re.search(r"[ ][a-zA-Z][a-zA-Z0-9]*([\.][A-Z][a-zA-Z0-9]*)*[ ]", checkType) + matchNameConv = re.search( + r"[ ][a-zA-Z][a-zA-Z0-9]*([\.][A-Z][a-zA-Z0-9]*)*[ ]", + checkType, + ) checkType = checkType.strip() - self.assertIsNotNone(matchNameConv, file + " in line " + str(i) + ": field message type wrong. Check: '" + checkType + "'") + self.assertIsNotNone( + matchNameConv, + file + + " in line " + + str(i) + + ": field message type wrong. Check: '" + + checkType + + "'", + ) # Search for a closing brace. matchClosingBrace = re.search("}", statement) @@ -269,12 +341,20 @@ def test_field_type(self): if matchEnum is not None: isEnum = True - endOfLine = statement[matchEnum.end():] + endOfLine = statement[matchEnum.end() :] matchName = re.search(r"\b\w[\S]*\b", endOfLine) if matchName is not None: # Test to check presence of invalid special characters - matchNameConv = re.search(r"\b[A-Z][a-zA-Z0-9]*\b", endOfLine[matchName.start():matchName.end()]) - enumName = self.convert(endOfLine[matchName.start():matchName.end()]) + "_" + matchNameConv = re.search( + r"\b[A-Z][a-zA-Z0-9]*\b", + endOfLine[matchName.start() : matchName.end()], + ) + enumName = ( + self.convert( + endOfLine[matchName.start() : matchName.end()] + ) + + "_" + ) # Search for a closing brace. matchClosingBrace = re.search("}", statement) @@ -283,7 +363,7 @@ def test_field_type(self): enumName = "" def test_field_multiplicity(self): - ''' Test to check if every field has the multiplicity "repeated" or "optional". ''' + """Test to check if every field has the multiplicity "repeated" or "optional".""" for file in PROTO_FILES: with open(file, "rt") as fin, self.subTest(file=file): @@ -294,7 +374,6 @@ def test_field_multiplicity(self): saveStatement = "" for line in fin: - # Skipping test on multiplicity for protobuf 3.0.0 if '"proto3"' in line: break @@ -307,8 +386,8 @@ def test_field_multiplicity(self): matchComment = re.search("//", line) if matchComment is not None: - statement = line[:matchComment.start()] - comment = line[matchComment.end():] + statement = line[: matchComment.start()] + comment = line[matchComment.end() :] else: statement = line comment = "" @@ -327,8 +406,8 @@ def test_field_multiplicity(self): saveStatement = statement statement = "" else: - saveStatement = statement[matchSep.end():] - statement = statement[:matchSep.end()] + saveStatement = statement[matchSep.end() :] + statement = statement[: matchSep.end()] if isEnum is False: # Check if not inside an enum. @@ -338,10 +417,13 @@ def test_field_multiplicity(self): if matchMessage is not None: # a new message or a new nested message noMessage += 1 - endOfLine = statement[matchMessage.end():] + endOfLine = statement[matchMessage.end() :] matchName = re.search(r"\b\w[\S]*\b", endOfLine) if matchName is not None: - matchNameConv = re.search(r"\b[A-Z][a-zA-Z0-9]*\b",endOfLine[matchName.start():matchName.end()]) + matchNameConv = re.search( + r"\b[A-Z][a-zA-Z0-9]*\b", + endOfLine[matchName.start() : matchName.end()], + ) elif re.search(r"\bextend\b", statement) is not None: # treat extend as message @@ -352,18 +434,38 @@ def test_field_multiplicity(self): if noMessage > 0: matchName = re.search(r"\b\w[\S]*\b\s*=", statement) if matchName is not None: - checkName = statement[matchName.start():matchName.end() - 1] + checkName = statement[ + matchName.start() : matchName.end() - 1 + ] # Check field message type (remove field name) type = statement.replace(checkName, "") matchName = re.search(r"\b\w[\S\.]*\s*=", type) if matchName is not None: - checkType = " " + type[matchName.start():matchName.end() - 1] + " " + checkType = ( + " " + + type[ + matchName.start() : matchName.end() - 1 + ] + + " " + ) # Test to check nested message type - matchNameConv = re.search(r"[ ][a-zA-Z][a-zA-Z0-9]*([\.][A-Z][a-zA-Z0-9]*)*[ ]",checkType) + matchNameConv = re.search( + r"[ ][a-zA-Z][a-zA-Z0-9]*([\.][A-Z][a-zA-Z0-9]*)*[ ]", + checkType, + ) statement = statement.strip() - self.assertIsNotNone(re.search(r"\boptional\b", type) is None and re.search(r"\brepeated\b",type), file + " in line " + str(i) + ": field multiplicity (\"optional\" or \"repeated\") is missing. Check: '" + statement + "'") + self.assertIsNotNone( + re.search(r"\boptional\b", type) is None + and re.search(r"\brepeated\b", type), + file + + " in line " + + str(i) + + ': field multiplicity ("optional" or "repeated") is missing. Check: \'' + + statement + + "'", + ) # Search for a closing brace. matchClosingBrace = re.search("}", statement) @@ -375,12 +477,20 @@ def test_field_multiplicity(self): if matchEnum is not None: isEnum = True - endOfLine = statement[matchEnum.end():] + endOfLine = statement[matchEnum.end() :] matchName = re.search(r"\b\w[\S]*\b", endOfLine) if matchName is not None: # Test to check presence of invalid special characters - matchNameConv = re.search(r"\b[A-Z][a-zA-Z0-9]*\b", endOfLine[matchName.start():matchName.end()]) - enumName = self.convert(endOfLine[matchName.start():matchName.end()]) + "_" + matchNameConv = re.search( + r"\b[A-Z][a-zA-Z0-9]*\b", + endOfLine[matchName.start() : matchName.end()], + ) + enumName = ( + self.convert( + endOfLine[matchName.start() : matchName.end()] + ) + + "_" + ) # Search for a closing brace. matchClosingBrace = re.search("}", statement) @@ -389,6 +499,5 @@ def test_field_multiplicity(self): enumName = "" def convert(self, name): - s1 = re.sub(r'(.)([A-Z][a-z]+)', r'\1_\2', name) - return re.sub(r'([a-z0-9])([A-Z])', r'\1_\2', s1).upper() - + s1 = re.sub(r"(.)([A-Z][a-z]+)", r"\1_\2", name) + return re.sub(r"([a-z0-9])([A-Z])", r"\1_\2", s1).upper() diff --git a/tests/test_invalid_punctuation.py b/tests/test_invalid_punctuation.py index 224411322..e658d624d 100644 --- a/tests/test_invalid_punctuation.py +++ b/tests/test_invalid_punctuation.py @@ -3,12 +3,17 @@ PROTO_FILES = glob.glob("*.proto") + class TestInvalidPunctuation(unittest.TestCase): - ''' Test class to check invalid punctuation character '__' ''' + """Test class to check invalid punctuation character '__'""" def test_invalid_punctuation(self): - ''' Test to check invalid punctuation character '__' ''' + """Test to check invalid punctuation character '__'""" for file in PROTO_FILES: with open(file, "rt") as fin, self.subTest(file=file): for i, line in enumerate(fin, start=1): - self.assertEqual(line.find("__"), -1, file + " in line " + str(i) + ": not permitted use of '__' ") + self.assertEqual( + line.find("__"), + -1, + file + " in line " + str(i) + ": not permitted use of '__' ", + ) diff --git a/tests/test_invalid_tabs.py b/tests/test_invalid_tabs.py index 4b55f58f8..f6c61853f 100644 --- a/tests/test_invalid_tabs.py +++ b/tests/test_invalid_tabs.py @@ -3,12 +3,17 @@ PROTO_FILES = glob.glob("*.proto") + class TestInvalidTabs(unittest.TestCase): """Test class for invalid tabulators""" def test_invalid_tabs(self): - ''' Test to check if invalid tabs exist. ''' + """Test to check if invalid tabs exist.""" for file in PROTO_FILES: with open(file, "rt") as fin, self.subTest(file=file): for i, line in enumerate(fin, start=1): - self.assertEqual(line.find("\t"), -1, file + " in line " + str(i) + ": not permitted tab found") + self.assertEqual( + line.find("\t"), + -1, + file + " in line " + str(i) + ": not permitted tab found", + ) diff --git a/tests/test_newline.py b/tests/test_newline.py index 1260659f7..fbc0a30e1 100644 --- a/tests/test_newline.py +++ b/tests/test_newline.py @@ -3,12 +3,17 @@ PROTO_FILES = glob.glob("*.proto") + class TestNewLine(unittest.TestCase): - ''' Test class for mandatory new line. ''' + """Test class for mandatory new line.""" def test_newline(self): - ''' Test to check last line of file must end with a new line. ''' + """Test to check last line of file must end with a new line.""" for file in PROTO_FILES: with open(file, "rt") as fin, self.subTest(file=file): lastCharacter = fin.read()[-1] - self.assertEqual(lastCharacter, "\n", file + " has no new line at the end of the file.") + self.assertEqual( + lastCharacter, + "\n", + file + " has no new line at the end of the file.", + ) diff --git a/tests/test_non_ascii.py b/tests/test_non_ascii.py index ccfc76acb..db6656fd0 100644 --- a/tests/test_non_ascii.py +++ b/tests/test_non_ascii.py @@ -5,15 +5,34 @@ PROTO_FILES = glob.glob("*.proto") + class TestNonAscii(unittest.TestCase): """Class is checking if there is an "Umlaut" or any non ASCII characters are present.""" def test_non_ascii(self): - ''' Test if there are any non ASCII characters present like an "Umlaut". ''' + """Test if there are any non ASCII characters present like an "Umlaut".""" for file in PROTO_FILES: with open(file, "rt") as fin, self.subTest(file=file): for i, line in enumerate(fin, start=1): - if (sys.version_info >= (3, 0)): - self.assertEqual(line, unicodedata.normalize('NFKD', line).encode('ASCII', 'ignore').decode(), file + " in line " + str(i) + ": a none ASCII char is present") + if sys.version_info >= (3, 0): + self.assertEqual( + line, + unicodedata.normalize("NFKD", line) + .encode("ASCII", "ignore") + .decode(), + file + + " in line " + + str(i) + + ": a none ASCII char is present", + ) else: - self.assertEqual(line, unicodedata.normalize('NFKD', unicode(line, 'ISO-8859-1')).encode('ASCII', 'ignore'), file + " in line " + str(i) + ": a none ASCII char is present") \ No newline at end of file + self.assertEqual( + line, + unicodedata.normalize( + "NFKD", unicode(line, "ISO-8859-1") + ).encode("ASCII", "ignore"), + file + + " in line " + + str(i) + + ": a none ASCII char is present", + ) diff --git a/tests/test_rules.py b/tests/test_rules.py index d20c96e29..8f8dac7bd 100644 --- a/tests/test_rules.py +++ b/tests/test_rules.py @@ -5,15 +5,16 @@ PROTO_FILES = glob.glob("*.proto") + class TestRules(unittest.TestCase): - """ Test class for units documentation. """ + """Test class for units documentation.""" def test_rules_compliance(self): - ''' Test rule compliance syntax of proto files. ''' + """Test rule compliance syntax of proto files.""" - with open(r'rules.yml') as rules_file: + with open(r"rules.yml") as rules_file: RULES_DICT = yaml.load(rules_file, Loader=yaml.BaseLoader) - + for file in PROTO_FILES: with open(file, "rt") as fin, self.subTest(file=file): line_number = 0 @@ -30,8 +31,8 @@ def test_rules_compliance(self): # Search for comment ("//"). matchComment = re.search("//", line) if matchComment is not None: - statement = line[:matchComment.start()] - comment = line[matchComment.end():] + statement = line[: matchComment.start()] + comment = line[matchComment.end() :] else: statement = line comment = "" @@ -50,18 +51,22 @@ def test_rules_compliance(self): saveStatement = statement statement = "" else: - saveStatement = statement[matchSep.end():] - statement = statement[:matchSep.end()] + saveStatement = statement[matchSep.end() :] + statement = statement[: matchSep.end()] # Search for "message". matchMessage = re.search(r"\bmessage\b", statement) if matchMessage is not None: # a new message or a new nested message numMessage += 1 - self.assertFalse(foundruleCount > 0 or lineruleCount > 0, file + f" in line {str(line_number-1)}: message should not have rules for '{statement.strip()}'") - endOfLine = statement[matchMessage.end():] + self.assertFalse( + foundruleCount > 0 or lineruleCount > 0, + file + + f" in line {str(line_number-1)}: message should not have rules for '{statement.strip()}'", + ) + endOfLine = statement[matchMessage.end() :] matchName = re.search(r"\b\w[\S]*\b", endOfLine) - + elif re.search(r"\bextend\b", statement) is not None: # treat extend as message numMessage += 1 @@ -70,7 +75,9 @@ def test_rules_compliance(self): if numMessage > 0: matchName = re.search(r"\b\w[\S]*\b\s*=", statement) if matchName is not None: - checkName = statement[matchName.start():matchName.end()-1] + checkName = statement[ + matchName.start() : matchName.end() - 1 + ] # Check field message type (remove field name) type = statement.replace(checkName, "") matchName = re.search(r"\b\w[\S\.]*\s*=", type) @@ -78,17 +85,25 @@ def test_rules_compliance(self): if isEnum: matchName = re.search(r"\b\w[\S:]+\b", statement) if matchName is not None: - checkName = statement[matchName.start():matchName.end()] - self.assertFalse(foundruleCount > 0 or lineruleCount > 0, file + f" in line {str(line_number-1)}: enum field should not have rules for '{statement.strip()}'") + checkName = statement[matchName.start() : matchName.end()] + self.assertFalse( + foundruleCount > 0 or lineruleCount > 0, + file + + f" in line {str(line_number-1)}: enum field should not have rules for '{statement.strip()}'", + ) # Search for "enum". matchEnum = re.search(r"\benum\b", statement) if matchEnum is not None: isEnum = True - endOfLine = statement[matchEnum.end():] + endOfLine = statement[matchEnum.end() :] matchName = re.search(r"\b\w[\S]*\b", endOfLine) if matchName is not None: - self.assertFalse(foundruleCount > 0 or lineruleCount > 0, file + f" in line {str(line_number-1)}: enum should not have rules for '{statement.strip()}'") + self.assertFalse( + foundruleCount > 0 or lineruleCount > 0, + file + + f" in line {str(line_number-1)}: enum should not have rules for '{statement.strip()}'", + ) # Search for a closing brace. matchClosingBrace = re.search("}", statement) @@ -106,7 +121,7 @@ def test_rules_compliance(self): lineruleCount = 0 foundruleCount = 0 - if not endRule and comment != '': + if not endRule and comment != "": for rulename, ruleregex in RULES_DICT.items(): if re.search(ruleregex, comment): foundruleCount += 1 @@ -115,10 +130,49 @@ def test_rules_compliance(self): if numMessage > 0: if statement.find(";") != -1: statement = statement.strip() - self.assertFalse(hasRule and lineruleCount != foundruleCount and endRule and lineruleCount-foundruleCount-1>0, file + " in line " + str(line_number) + ": "+str(lineruleCount-foundruleCount-1)+" defined rule(s) does not exists for: '"+statement+"'") - self.assertFalse(hasRule and not endRule, file + " in line " + str(line_number) + ": \\endrules statement does not exists for: '"+statement+"'. Check spacing and rule syntax.") - self.assertFalse(not hasRule and endRule, file + " in line " + str(line_number) + ": \\rules statement does not exists for: '"+statement+"'. Check spacing and rule syntax.") - self.assertFalse(not hasRule and not endRule and lineruleCount < foundruleCount, file + " in line " + str(line_number) + ": rules found but no statements (\\rules and \\endrules) around it for: '"+statement+"'") + self.assertFalse( + hasRule + and lineruleCount != foundruleCount + and endRule + and lineruleCount - foundruleCount - 1 > 0, + file + + " in line " + + str(line_number) + + ": " + + str(lineruleCount - foundruleCount - 1) + + " defined rule(s) does not exists for: '" + + statement + + "'", + ) + self.assertFalse( + hasRule and not endRule, + file + + " in line " + + str(line_number) + + ": \\endrules statement does not exists for: '" + + statement + + "'. Check spacing and rule syntax.", + ) + self.assertFalse( + not hasRule and endRule, + file + + " in line " + + str(line_number) + + ": \\rules statement does not exists for: '" + + statement + + "'. Check spacing and rule syntax.", + ) + self.assertFalse( + not hasRule + and not endRule + and lineruleCount < foundruleCount, + file + + " in line " + + str(line_number) + + ": rules found but no statements (\\rules and \\endrules) around it for: '" + + statement + + "'", + ) lineruleCount = 0 foundruleCount = 0 @@ -128,5 +182,6 @@ def test_rules_compliance(self): if hasRule and not endRule or not hasRule and endRule: lineruleCount += 1 -if __name__ == '__main__': + +if __name__ == "__main__": unittest.main() diff --git a/tests/test_units.py b/tests/test_units.py index 2bcd4ac9d..dea7ce784 100644 --- a/tests/test_units.py +++ b/tests/test_units.py @@ -4,25 +4,54 @@ PROTO_FILES = glob.glob("*.proto") + class TestUnits(unittest.TestCase): - """ Test class for units documentation. """ + """Test class for units documentation.""" def test_no_brackets(self): - ''' Test to check if units have the right syntax. ''' + """Test to check if units have the right syntax.""" + + NOT_VALID_BRACKETS = [r"\(", r"\)", r"\[", r"\]", r"\{", r"\}"] - NOT_VALID_BRACKETS = [r'\(', r'\)', r'\[', r'\]', r'\{', r'\}'] - for file in PROTO_FILES: with open(file, "rt") as fin, self.subTest(file=file): for i, line in enumerate(fin, start=1): - found = re.search('Unit:', line, re.IGNORECASE) + found = re.search("Unit:", line, re.IGNORECASE) if found: comment_list = line.split() - self.assertEqual(comment_list[0], '//', file + " in line " + str(i) + ": Unit must be on a separate line or have a space between //. (Example: '// Unit: m')") - self.assertEqual(comment_list[1], 'Unit:', file + " in line " + str(i) + f": '{comment_list[1]}' do not match 'Unit:'. (Example: '// Unit: m')") - self.assertGreaterEqual(len(comment_list), 3, file + " in line " + str(i) + ": No unit defined. (Example: '// Unit: m')") - + self.assertEqual( + comment_list[0], + "//", + file + + " in line " + + str(i) + + ": Unit must be on a separate line or have a space between //. (Example: '// Unit: m')", + ) + self.assertEqual( + comment_list[1], + "Unit:", + file + + " in line " + + str(i) + + f": '{comment_list[1]}' do not match 'Unit:'. (Example: '// Unit: m')", + ) + self.assertGreaterEqual( + len(comment_list), + 3, + file + + " in line " + + str(i) + + ": No unit defined. (Example: '// Unit: m')", + ) + for unit in comment_list: for brackets in NOT_VALID_BRACKETS: - self.assertNotRegex(unit, brackets, file + " in line " + str(i) + ": Invalid brackets around units.") + self.assertNotRegex( + unit, + brackets, + file + + " in line " + + str(i) + + ": Invalid brackets around units.", + ) From 2db24fb39fc0017c460c66785523a63265009bff Mon Sep 17 00:00:00 2001 From: Fabian Pfeuffer Date: Fri, 27 Jan 2023 17:47:42 +0100 Subject: [PATCH 009/113] feat: New OSI message osi_route The new message allows sending route information to a traffic agent in the simulation. The route information can then be used by the agent to traverse the road network. Signed-off-by: Fabian Pfeuffer --- CMakeLists.txt | 1 + doc/images/OSI_Planned_Route.png | Bin 0 -> 22780 bytes doc/images/OSI_Route_Segment.png | Bin 0 -> 17096 bytes osi_hostvehicledata.proto | 5 ++ osi_route.proto | 123 +++++++++++++++++++++++++++++++ setup.py | 1 + 6 files changed, 130 insertions(+) create mode 100644 doc/images/OSI_Planned_Route.png create mode 100644 doc/images/OSI_Route_Segment.png create mode 100644 osi_route.proto diff --git a/CMakeLists.txt b/CMakeLists.txt index 8c9626321..6057fddf8 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -85,6 +85,7 @@ set(OSI_PROTO_FILES osi_trafficcommandupdate.proto osi_referenceline.proto osi_roadmarking.proto + osi_route.proto osi_lane.proto osi_logicallane.proto osi_featuredata.proto diff --git a/doc/images/OSI_Planned_Route.png b/doc/images/OSI_Planned_Route.png new file mode 100644 index 0000000000000000000000000000000000000000..17e490cedea144709d52d5634133986563209348 GIT binary patch literal 22780 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 Y=3KtLCv?vZ@bv$<{V6;4@7_264{_EPLjV8( literal 0 HcmV?d00001 diff --git a/doc/images/OSI_Route_Segment.png b/doc/images/OSI_Route_Segment.png new file mode 100644 index 0000000000000000000000000000000000000000..be13b5672a11cffb727446af9fe34055a58e6140 GIT binary patch literal 17096 zcmeIYcT`l{vM=0#f`SA^L_jh~&N+ifmY|^I&@@dD=tk(4oJ0gkB1w>pf`kS{l4Jyw z90bYGNRCa;O?a!>`|Pvtch7gXzlxEV-c0uVCY}P;Cfu&B}<*wxfqGA527#H`5D(R zjM+)KJ3OyT5V_+EIX(VyLKcU0f3dO0NEyGI#I(MlxFe(2K9#h(c)pif6f?aU?@W+15<2MTeB}ZE)4JR)fN(%+<_-P#U8d~0d z$p|lli~EHr$xO*~z(*Yw(x>(|v2+?|(vt$8{7v2tr5|=SpzJHAUi6(G*0>*d_u9F~ zzPMfPE3pR&=Q`wpnUTFXDEU#m%~3maAajU`3xB&p&&Th_7a6Cqr7eaL9Uxtf){B5UxZnuAX|Cn96D5(J-P0xW%u(lB!eQI_ z5#3pj_W8RBYp(4{={ zePtAL*7(HpHU9*Mtp8Kq5SOpJp_f z3@jjI%IzQj%*i(o>9O#_^qUT&u}f}q53L|HakER12&p7D;cX|d>-k(qM**tZraZf# zxFiRUvEc5|gTnF8RXhC2(rD+^b?-ILemu=j3|BwV%biAu2pHAO5Ajr**PTYm_}gNV z2hX>#a2r0~(ge$#6Zz95v7&sxwB}}#Adj9lqoUUl1$H1syI$k9yrH$Eos{p>aa>6% zVT-n(B=tMR;=CRuB>OF_zv((P^&}}g>#Ut`NUr*whxNBzpXa-Cq>nyhaU377_^vDF zMdkGXl6ed(Ny2s^8m;5nupu3%J0cMZwX8xn1xi0^QaBop{M`K^_0gD+f3Xc^_vVA# zXA6trpHVjCKeIk@j@Os&iK%60=G?6sugi^eZ7mYl`NH>FNPBoxZFmLzJpR_Zn8z5R zl?R@^CF?9vHaQqinW}b7SIV3YXejtHnk;qfVdN9;NJ*YF2^JauiZ2t?!sFOcQDG1q;8;0AZQ`xFAbq<4xmx(H>tL6=~d| zy*r`P9w%Y&b;0la^9+-u+!l66gYCZFw97neV{CL8hDofG2lA1JOSw1NqR|Px6b)u% ziZvjkeqKA#^=>nhcd||iwNvInf|G-t<__i{doLL0^MJiVrxvicuTm^~n#`kMuHl~D z%9_?imdhxWF?cg+UEpT~Xnr~+zI=Il#of6Uv=fjb>O{mb;ri~Hzdxn(i&NnqUx`CC zJ@?ATucW*j>r~{jE{k(i*DNIQ=@5%(imAhhK_;$_mi4d@Jj%<8t^$zjAG&Q3FG32e z#HmUvmnnA`h#w*cTE5o5;&IE&!E&cT8gBISH|^UkL!zk1YRDx!`v^pcgKIsaZq{oM zs1kYzD-Mg@;E_xHLQoC1ySWRRyoUGiTToJJkX#?Z<@mI9dn-phYj1jWc$!09mqBEh z^b$(ry=KNWkV-HZ?3ipyFdL#)m?UtjyvuPpvS_t)!*z;Kg$5SeI<{`eSKK}H>nkRLzp2Rb@ zN&}4i%_Ex6WUjworBp`Ec#obc9ZYAT`tO=da7LxveW)x&(SJoq_R2o>HQT=G+Dm+9 zL}SZ68TUM$kNeFdw8r!8p1^{X*lB~TBltH{;^cygB!@Hkzu-;VUwN+BTNbw-6DHAk z)69hUUOnFvU(%*EpUquZi8dEiR|AP;_F6XU2#j+bF~%E2Pi<* zCP#hv)79AQ1i5>YlOL`xe=Hs{nN;PFCJmEa6}+i3EHa7_6?)|V?HkwlQS=ucndcmq zb`x3n(xbjrV7$}k3|EXeD?ZrZNF2Y+sz%1{jpVer*kD7g83(CfxV3m!;BG{M3+~$dDhr!h-`+>To*JRhu z4c4w%EuM2BwU1wGwnsaCob)s$aCx@){k_>s!m$UxT3@0h7QiM#{e&CjqCavV$6=Y- zB(da)W5vpm6wE@ftc#;f-g!<^WW%@Hw7ATH932PM!zoGD&Xt?6*PPsZXr$RwH66mROaFE+DJWR zxuo=T^t5q_a}%BN)~=Jy2`Lw{`|`3`tYV7WHCGl#OdZdf8fgxxJFWM}FN(6KAMW}4 z${?=awrCe2f2$+LIzqw_z;<<}r{XP*0vB_THOY&B3RzDw*0AU+unCbzu7RPt^-eb; zsCrf(RSv+fq%~B?e0Hbip5vpmZYCqw{%uv$P`syiNAzreQ`f=qH#qxp?vBwAaDWUiI9sI(V8Yw)2)2G-ZO9iVx&3N#cDaBJt6Tq95+!^`q4jB*N?KFM8-t7*e~H`W#&J zd@203^{NNS`-gU&Q%82DRD5a0^y0^Ga7nzIlNt{utv;&$7!9Sa3nr_Ws-Kh-yaS<$cC>@?6DB}MZIKVLfCK$P+Fq!(rx@fLm- z{5-nSFP?O8rcb{AS>DG;pyU z@IY8MlY?ZBII63YDm@}BYJ@i~Ny3reuW(BHzIht^!hF2yPa2gybsDOryJ2Ta8d)h` zbspxqBKBdNC>a4w3XUP_v`b~oHnwvKuOLk*#Wou}Q~bwPp@G-UrHU4KJ2~(?I7QEn zVBc8SWZNXG;%`_MH-z5I3Vk@YOXbD;*0zc;n*7%5_gSj=5tj?ep$t22{1bZ` zYt)m!Kgr$<&YX>)>gRc=D(e10=~32tTAIgV`;!dA0vV!P%G0-=`vwTzI2MOY%(>DI zO62&2-5$L+C}H?nH$;zuk0;=P5qPBU#tT-%mmlzcdeF8clz2H>a;(}U)IJ%c7uAlw z_0z>R8o?Ita(tEd$~ckND-P+}I!o1x0>HHUA<9a4*`2uPA%>s+?Tg`#9NDg)Pbt|v9sZ2CtAAE}!i z%wCt{7k-`>Kd%>1wA*`yUvTr232}DPCoP_4{{YfB4i@*H8d+egyPcc0*BkE7uc(6g zCc4t@*TWIwYk7>b$~!r3-;_e@RUK*9&pBO&6idW|cfYHl1Coa6y)iw+VSeHy;1tVY zDT#xU^$O~NUaPTM$ zQr?8~-ryzMP`u5rFkaB?wupX57}Ru)_tp(Y1GOL(9#JCi>o?s4EB$f_93CT%53gJj z)z40kT;1*L>yse9rAS<+6?ikdc+7%WGAn&tGixD$)5hZxn`ka=r{ROACWv}bIpffq z4=Ct4T&{O?`gL4+hRsvnDkXSFs;5Z5Awt5{{Qjh^EqWN?CQVfFIub;s5QZ1Mj=z~^ z;jpA2ykX()Yc>WYq{YK5-YeM%B@n&#>DN2`=Y~_@6tf7%VCJR!KJ@aM;;&1sNd=}a zuSI>Rc`EC7Mz*ChQG)Q1lk1nzE}iu|C~Hi<((&UX-K+O2lYTIi0ogUJ%UaK+IErdF zDUqK1*B+~>hLad4J~7Q!LPw>KdURZh^gI?C?Caatm-x!gh15{^fqi>w82M8-`R*9v ziNupcPK8(dBD2eOZ*N~=qyIPq&Q#5`UPS&PJSDpxZBKu5A%1>6c3yiWH6irriyi!| z56tS02O9$}3M3DyjzqQ7-m47gQ#9)mE`bdO_8s)%#Y4Pj<@>h9tR(cb4O-kGO*)a)MR z`~X?uB@t3bJ?gL50%2wiX0qnQh&|;J#$Bf9iDPq zyGqUR*KyXC{@r2IQ8G@h%1@WYt-d9miR=cxv+mkOXnVYz7Ej~LOW@^vfL=aj!ZRcD z5{bTHBut@Aa*98>mG{I&&Zzn7`JNd#bGFqTabG={V(&C6>KV^h^6@e%GZ4X13AaJ) z)K&Z*>Q1Wb*Us1j>mVjBy)Rqo!$p|!A-iX-p1=JTGtMTj-Mj=oYjpV{}Q582IaP&2suY+?za?13G~~TROAb3X%>&Jah(3$(HWAp@R>-RvkdQw8udML5BmL=75BeQ zTlUHJl!of=u(}q!DW@160o#z?is3doBmHLblGwH)&P!?S*z=NP_J$wXVu@_}o2F6= z%)&s{H|H)zcH$@5ddj;+_G))HO_yIOP7TwTABya5Ti;bq7ZFEEE}TVJJS6-D)!RnQ zd}t(Fs5n}dBHrXRIFEbDIR1Hg!*CB71l@-M+p)~=S}e(CgZ zgz_V(eEzgiM$(nUQSi%n?1Ka4(rWP7X6J7R!7`EjGb!awd&G@=GNqKr-`p)PE4Ias zlM;DNgion5Nigbrss^WKw%1E)@tLwO{kH4tDxjTJ@FqL|9fTy15jB{-kyYKBtG300 zpjIf56ssX&y?${?jOR{cYkX7+?bCBI$pN_veo6_f`H&!U2M!<=L63II&HxY%F22g%F6#}t^s;deBa8cH|yOD)-}z}dQ2n}8fuf9${QLc z`IIV5kNFpIp>$&HF8O;=HZK0C7mnY)rGL*43NI}pD|*3nNHDW9^KprV9sTa6NsGty zmV8gm;wIWRpuxg6e^iJp_dWFEjc3fU=2S0=H^GgR@BMg@Qhz_Z7~VVn);rD zjFKc+JYhVMiZtFMOfoB%b{;Fj&y!LqSuoG-h>mR#j2n28P^IH|`zo*XRhCO_xmhoT zd0Xs<)rH<>?R*XKZ`%r=i)nw1&)SO5t;a0ox2bR_XDXr~HGMaDMsYFR**^mRn|a2= zQp^Tq9F_tKwEL~;c*KLWT8P~>(F(tVcRJqq9jO(25YS0)wW;y$TKil4vXdj(O+VGC zxXXmFz;!WqShrh>Jjmhw<84Ao$xB(6J1h=7+zqi4XBdZ`4I;B1*EELm#dQ#f{JsOw z?KIMUAPs>#^Mh^R)=+*AXBQwgKp)(~S zI3eBst`q47#gQ)TcCxV*0F1iO{C62O4Q;)@WN>b@b8vRKkic>Oozn*L7oQ8#)#-xA z1|k4;f;t0+xBF37g95<$9RM5=K~WJ& zYat0f5wIYHPgD#n%4aPC;D~~)C2d3`M8u$i!heI%b#(wj8|?IVt8h>@0F*UE#705{ zEWsx#ZX*alK_PsS5Nlv0Auc8?VrwfT42E7n;T$Wiq^BXrBFr!NPl}!s7-0){b(Uj! z-~dB<{By#Vv`6T=!~RG0|AO%kga-}~D9jE1Kbih_mOtF`w}JuK{09vv zL_l2=_^Yt}85X#m^Z)SQpW*iZPy+z{A0_{mfB)mI|G4Yl^1#2v{GaIhkGuXY5Byuq z|B0^uYwjZc=ch3g1|0OFhzOYJ`B9QQw??o%v4x$2^B>;?jnP~v{@ zK<`s-14JT(hPDdPA|3-NJv};*jshUjAXJPH%5Z1g#}Vky<2jSN1HzsOca}E{B%=m_ z=(jcQD;aoprC*ZHlap zwaCvesFqK6bB(Fwte)~ZmU}#Puw0qO9Z}8Xj0Xa7&#cl6VzA=3`9Yvu9cy|Js6`qC z`c;``hR-^L2g=Y?Hb)VF6sahIzpc`%{AGNyEcacjBf1BN)Sgs*P0(R*UFl+g~ss;>t$@_=V6cvh8syM>KYX;A7 ztGF+!n8aFFi9@3p1UjV*VgeM$*{4MhOe=a2^tCDq7=8q% zr%4sbn`>_b0@5!f0&Z^vYpMX?FC{=!?o)?7K}UJW!K#M%D7O-_EARkX65|!tuJ6)J z^?29AZ*P3a(=Q&I_vNqMT#4~1ZptO;Ur-~u0;j0d)9CK*lyRbq?MXByYLN)F&X={h zz8bJeh!+`s8HYqM)O3qtm8n|Ep2S)aMbJc-$(MoGB7MdAw#zp@6fn9+_p-8&5MU|0 zjxN8BzDK8sV$D!Oggb*;s_hA%O4J8SfRI$HEYvS6HwiOxAm)AeGo~H{df6qgE5MpS z*7OwU89E>`m}>EG3QTu6i zg#{o$CkP~GB?j!acxL$ z066!{m|i{od|WuZnAUxs=GGZVcppWew*lrW!Yd&QXj>0VhM#GEs!aDkgU-<9ng(;} z=XiAT1&r`(*}D(-yfAy&+&CnO2}|+$wR@AeP-8XHxXxA`R_|6DINH@Et(dCjZmC>T zEX3cISx?GX!QV<>;+(n{U#xv|)tcVQO2wW1MUB8i{vUxwWfix=DoBE#1hD`CSjkD0 z&oVSlE8TM3Xk_QR@@s!Mpx&=P&xnW<;xl~DBiuDZq0mBx4Y!~&sxLm@4@&)-8`}o> z-lB)?4+!-YJ%%*^rt0mXN$R=7>r-9smS-Wn6QZc$11>fxo6Q0#MCGCgta6#gzyoN~ z93d=VTg(!O-jrgp2`wuxIt;Lfr_I&wOU>{8$cdMF{-#v~KAHR_e-D%NwUv+XviK_I zL5&g7Q~CN;v087+g{%};FR$59+0za#jTn7*e{?`2e^#B$H~yi(d}8<(UsvGqmo4h_ zp5<2g=#PA#Qn8UvPaWDKE9niWf1*>3pO=uuiPZ;J3KESZ{diT8g&dM7U(=^9srUW3 z!8`U{`U(yL@3=c^6$MAt2#pw*g(GtZmTsY&?qtw9J>|2otIPbH18Z&S0$5*4DL$q- zPIDX^HrD;(b3}eE6o~goL89Ed2iMZyvL(3<1QIHvls%PA5hQM4vH+tH;gE{os)+&|Shv~EjpZRN^}DeER!Rpt`-o6D^V4tr(QiQ5{?R3bM#>Dywg3Xy{2#bheicaf^J` zoq(s}iv@**nGlq2QvbriHEYW`eGw%!t;H?0qOqnsT4EhAasU7i3|iK z-cA)N)oI_eCA9oKY#Bk~3aXG?*WKv(oLLYvL>J3eIVHm!o*=fjDzBY7b|AriHmk5c zA`wn4u<>)4V)d8P@9>iqvS&hMdgDcs$EERDTLH@ir{e?XV#cWxg9TZcE^=o6piE7J zl^gUWQeg;eugk_Bda9YixhtCGy}HiW%{7)L zH{D7mn6Y-$QZ+otJZ}iwT6^|Tr zWMKpZj?H3hx^=Pg-emFZKqX$pMDX|*ECh# zJo(_SW+L(NV{f83q~@ar*3TyLrzP|?^7y?e<`jE@>>tCnn11RXUI9NF4Iw24Q9*5S zrBDy5BRlgtVgh1J>^!9&GlBj6waZfQS7QrQ5U7}?tYpW~A5rzztNXD#0+g%CVz=>u zJgV;)l1)cfSXv*Sgk;iiJ(>Q#ic&b40~1~j2(x!|=ynCxP7{5+3eG@J2fdv{!(0p$`lBqI%CKJ-t>PFf*;zsJ@6N47(OY#KXFaN0|` z`Wuo92U15%vpa?9yqzRk7Q?I9wbI3o6qmUmn#!qSVV@BK;~GEfTfFij2eJs;Cn$8c zVvrG$S7!(lp6}iwyn$Icgty1n|Es9K+2;3Jzm06qgZA_H;b;XuiHYatL(b9k2v|S! zPU%5fxbR%r>=*E4-Hw8Y&1S@eJSGh_#VNHkwks9F z=0>IwBPuavr-)!xMb-?ZN7Z;oH44;5_p z84ub|Mbv2i@D~@Q-NJ}OdP3{sdD#H;P9_iBtC>=2`*&$2tk}Xk&w72c{8AWoumMUr`ZBzeBUUQHKs=T7NdGE! z5V>nN7EvKT^+|4}SS(}L$k9~!8Oqeo9L3RoxMjJ#bv`iRll0*gUc2-vX!qShFj02q zbdl4@XVW2671vIhcdF9pja9o!pXVWT=^nH8tolujQ)utIx}85rKRHjM|w*KO+q5-3>xa>@oA zvI#I$&zD$Y65(rV$(pcE=f1U_g-PD1s%NvTKpj zBv(Ebj=zyV%JkW*33;-HeM4_r=U5%SNBcM|x;Q6bDyiNqtaLuIvWYPu&^!4b*Iij$4@nhxi&BaGo(pcs&gW zyi*SKWZ>FzGqLN`a)~ z>Kvw8rK;#nFXkWfTi&0%Ec+PTuU5=e51v|=6GQks<2}%b(0ZS{e`Wn$EXFSs!ujsp z18l|n#3&zF1J%$ovBX6v+n!}cX_ zFh_%}et6|InWMt@zFe;LDCYC7gZup4|046ARFgC%V@sZ7-Ug;jd!Rp1?KIXGLrvWv?~Xp0#XJ96L%D8U*W~r3ry5{f`S#^QPd5!mz31xw z$pU+gbdnRFGFX|Z6aLCs$V;4$I|~@xd3Kp6)SoT z)}8n|e7pMUjxge|)WMl1O{_SgbEcK7JAdIiA#F=_G~*KUM)kq=7PGpdC1!8oov_E7 zLF3KF664CbIMK+FL;@WT7NS%!v7Pm5&SJjXu;`^*f zx|=&MwH~Tp2@^2c4nEn0&9V$(zb)GC_8wrK-u25+sg)?iH+WZ(aBr+XaY#ERDD@6U z;gB))Dne$4$g8ntz0PgOm`F1}`r4?Q@4f;UW+Gn8tYusGEwL|qsN&w%^Z?V)cWETu zCV%R33UVm$k<^@WL;HF$);z{$;5cY!t+==2*zncu+ts@r9n(o-8$f~+khKwLXt74k(MmKT;pCQA@REv2P_}jnIhQvgP^T8Ku?z?L! zpM^p~!WQYl8=HIbSPMrycq%f(>}S2-Aeu(ny5t+EL`SR@t4Mr^?x{C)Yc$2xyH`qu zG}5l%q2h^QtG?{1sKZYwh`HTsFq7mr&i36aV$E(lsRP#{jEZYDQKc4IcnZ;WQ&`%~ z!5dqkN#ySuJG;U3{q}rnRp@Mf&Nccvajb4ytWps5VwD=&Az-P0b8_ewa4MN8f3vV4 zb8z8=W5-nFmW4Oo)Z-Qsj|?+1Y-2f4c3^`-p4&2Z$W{699LAKA*tGU~O8@knO#hA_ zT7K2l73voAYaC{>_b@p>H5^LmIF{v75$Cto~zq-*YMCu zkae#NMjAJO)nhDa6BCV#znYla)x96=T=RzG*Yl)aKKb~@LjTUH1n`l_y`cd3qs87} z!~_0HpeoRB(pzo*eQ^4m9zLjqY^F|{)o;4LVM%zYE{_Uy9MWmUy*4Ot6TWfe0O@C3 z!SpAg2~UbbJwTe%>&*JD$0g(+^MLx{Y~P-fkTc;iPC$6qc8I44J#1WjYfl-44;pM*i?A|TC+Ybml zqo!71mh*>fFk0pny{6t#tW$HU<7AUM`^+)WFU;BbPU5a}duoHP{^NDWYyu0EVIp$q zvX5Mgm;cM!45EjfjhnypWzgc!o;g^^FwmJE4`;Zx)&MT(l3pb+m9vl^&^I@Kq@N$X zq3v_U=aL}7o@ekn{7d3>$vuxzfmzL|Z^y@Y@0`X)gbV1Sl0t&pcOEn%hY^1>dOEm~fb zZ`Dy|LhCvPNbp6nIUeJWqC!0a-+%~XhAqojNP{Y%%NWZ$Nu&kD~z zrer%slj3>naWGGRUm2g)#^H7w%DY_8?ahZ@Kz>(h;TS!_9TfJB8mv@k3E`dnGR5>s z<($B)l7D*G0>G%$c&P?i}ugS=@ry0`9>IKpH{G>`To6hLt0V@r%5+ zcNv?8Dx0V6@ozl(Rde%O141L+C;}>uIlLwNhMgzb4j!FD7)xKr`#qjsP~(QhVSV~y zHTn;}SSyKAGB%AOxoi*YhM#Hu#^9h+Z8Q<*>CV%_#Nn8TQ5e>cl&AAdPN2Q0weW`0 z)UyO%EDiAD6=TLc6@n9qR`{$}ziV%3?2qt`e$Mm7E)d1kSQgcv^4it9i#PLMI3pDK zkUZ_gmYdKB8rXHkWm|@r=*==Drwn(tr@X&}bB8pl2+Ee{GpKtH^7v`6N zPp|HO+$~)jCjxpFF>D;Z&9_4h1J2w|9oo;l*@KeDD&f9@M`tgNqn?+b$pJ*r=MMu> znm;h5&fdo-Y$Q)th2pmR6ZuM4fryfqXa;&&h+ktSwQ{+c;*4rscB35pw^kc%7wEl@bm4GxmTb5 z1~Jzh!+O_g-0v)#O_#K`b#%ZAIAhtSB0&N4NHaU%&THOvl&gw20DXPEC1`N!-m9iY zUzA*uIS@-1)CSuw-Gssi;uU4^UK7F3jBxiL^NY=n2YSAnhh5zea_1QNjtg0OP{2AN zZfQoqF#qizgMhQWB#rhKg4mpHdD~T6rML+=!!U25Xjt|7#DUe zQXtUepw$%+D8t`8W**mDe)<~ddr zXoDQrsGZIBo+Vp@ar7N|>7zsAc7;=w{{9%Bc@4<@^TTB2Sn{+)Sy2h&YHq1hdkDVb zlv5Jhds*S5WXc%ww3rh+$aX!WQ%x`FCyvE>xhntXuJhzEi%;17eG#tf4(+S^>gZGR z5}nJwYv>uwXhE#!l-Bxb$Q-IN6nWfRu3L7l5tH02&H#$**)U{lIET9KDz(owhn@DV4b~v(tUXS5O`B6jL~zXIg^O)s&JMsnlTBhcEXSXZhik=L#oj#^d}j3~FKG`ZX{G*UDsgVelA}_7%5Qw4s@=b<@T6Y$ ztbHy(2y<>x$6s~E(f;Oa&TejG?Hoc0;+Ow$N}9Pi5yy)@Nj{%C<4mga-!}ZjZi$&* z9hiID{+)w;wza}Cx!!4@;(R|_CdOZ0;0W8Gezt&`3ubRmx!g|9sIl(-7&RPEJ+UIl}=j(5#{i$5(DP&0eCCdMh{*f19(64Ri-;XoVbv-MDcqt*7DAsM)Pd8Xa| zwWK{r*NJ40FU=w`#l`5LVF<~nQ8W(o{-NJ)iGJdfE^~{+-R#{7hPnNOO4dhEQ4q?2V`N(z@MpcQ+i%+o)Smk`tk;S=8Ok{h1e0$>CzamMYw@`g-EXF}3*3IwN-sze1^8?G|bziBY$;#NI zcN~mTB1h=8xlvN{DgUwl{iM@_)VLI3dC$46F-AkUASRPzm`(pII_0Q)KlqqjCgXe` z+VtCI;~{1v`qfihq$=zTar8FC-4UukjhTF8Je=TjF45jL8QWVA8OJCb>0!MqrN`Vn zuv5iF47X>whiaw?upVbr&BuDraRM1Wm? zLn}vqc5!xO4ajUx`oae*JsUf_;q4`sJ0keG9MligdcGPO(*$Z+>RmTL&BpXU^MiEi2M5rHDu!l|F0Fos7N5Y+TQswD-VuP+-h|)~uky z66o6icZBgjsynTKY^?bj=m1gx1qiq!0tL__H4-jv2cQ4ra*+w>8D8Az{GD)-wQ&TT zAdcgL034hDLi&r4s}*z&m^XMg+gf?T^7jQdC4|Ca(dWjI?dt~PNT|4sXUBm6t& qC{rfCyI7&^-xu`XAOrYM{U55-U?0s`=mA&6APp6r`$hMxUi>fRZtVvE literal 0 HcmV?d00001 diff --git a/osi_hostvehicledata.proto b/osi_hostvehicledata.proto index cdd723118..9467b72a8 100644 --- a/osi_hostvehicledata.proto +++ b/osi_hostvehicledata.proto @@ -4,6 +4,7 @@ option optimize_for = SPEED; import "osi_version.proto"; import "osi_common.proto"; +import "osi_route.proto"; package osi3; @@ -91,6 +92,10 @@ message HostVehicleData // optional VehicleMotion vehicle_motion = 13; + // Currently planned route of the vehicle + // + optional Route route = 14; + // // \brief Base parameters and overall states of the vehicle. // diff --git a/osi_route.proto b/osi_route.proto new file mode 100644 index 000000000..147c66f14 --- /dev/null +++ b/osi_route.proto @@ -0,0 +1,123 @@ +syntax = "proto3"; + +option optimize_for = SPEED; + +import "osi_common.proto"; + +package osi3; + +// +// \brief A route in the road network +// +// A route is an e.g. planned or suggested path for an agent to travel from one +// location to another within the road network. It is composed of a list of route +// segments, which form a continuous path through the road network and should be +// traversed in the order they are listed. +// The route allows the simulation environment to provide agents with high level +// path information, similar to that of a map or a navigation system, without the +// need for the agent model to perform complex path planning on its own. This +// allows for an efficient control of the agent's general direction, while +// simultaneously giving it enough freedom on how to traverse the path. +// +// ## Example +// +// The example below shows the \link Route route\endlink of a vehicle. +// +// \image html OSI_Planned_Route.png "Route" width=850px +// +// The route is composed of three \link RouteSegment route segments\endlink RS1-3, +// each indicated by a yellow outline. Two of the route segments +// (RS2 and RS3) only contain a single \link LogicalLaneSegment logical lane segment\endlink +// (highlighted in blue), while RS1 is composed of three +// logical lane segments (green, blue and red). +// +message Route +{ + + // The unique id of the route. + // + // \note This field is mandatory. + // + // \note This id must be unique within all route messages exchanged with + // one traffic participant. + // + optional Identifier route_id = 1; + + // Route segments that form the route of an agent. + // + // Consecutive segments should be connected without gaps, meaning that the + // two of them should form a continuous area. + // + repeated RouteSegment route_segment = 2; + + // + // \brief A segment of a logical lane. + // + message LogicalLaneSegment + { + // The ID of the logical lane this segment belongs to. + // + // \rules + // refers_to: LogicalLane + // \endrules + // + optional Identifier logical_lane_id = 1; + + // S position on the logical lane where the segment starts. + // + optional double start_s = 2; + + // S position on the logical lane where the segment ends. + // + optional double end_s = 3; + } + + // + // \brief A segment of a route. + // + // A route segment describes a segment of a traffic agent's route through the + // road network. The route segment is composed of a list of logical lanes + // segments that indicate the agent which logical lanes it should use in a + // given interval, so that it will eventually reach its destination. + // In general, only lanes should be listed that are parallel to each + // other, though some may have different lengths (e.g. if a lane widening + // occurs, the newly appearing lane will have a shorter length). + // + // Typically a route segment will be either + // - a set of lanes between two junctions, or + // - parallel lanes on an intersection with the same driving direction + // + // ## Example + // + // Consider the \link RouteSegment route segment\endlink between two intersections, + // shown in the image below. + // + // \image html OSI_Route_Segment.png "RouteSegment" width=850px + // + // In the example, a single route segment RS with three + // \link LogicalLaneSegment logical lane segments\endlink LL1, LL2 and LL3 is + // shown. The segments are indicated by the green, blue and red highlighted areas, + // one for each underlying logical lane The starting + // s-position of each segment is indicated by the yellow dotted line and the s- prefix + // (note that the start of LL2 lies further to the left, outside of the image), + // while the ending s-position of all segments is shown by the yellow dotted line e-RS. + // + // As it can be seen in the example, all logical lane segments are parallel, + // but two of them are opening at a later position, so their starting + // s-positions will be different. + // + message RouteSegment + { + + // Logical lane segments that form a route segment. + // + // The logical lane segments of a route segment should be connected without + // gaps, meaning that, together, the lane segments should form a + // continous area. + // + repeated LogicalLaneSegment lane_segment = 1; + + } + + +} diff --git a/setup.py b/setup.py index 36672287e..b09aee6c3 100644 --- a/setup.py +++ b/setup.py @@ -73,6 +73,7 @@ def find_protoc(): "osi_occupant.proto", "osi_referenceline.proto", "osi_roadmarking.proto", + 'osi_route.proto', "osi_sensordata.proto", "osi_sensorspecific.proto", "osi_sensorview.proto", From 02d086a2cd6f7fc500bc6ed2258503faf177fc6f Mon Sep 17 00:00:00 2001 From: Fabian Pfeuffer Date: Wed, 22 Nov 2023 10:16:59 +0100 Subject: [PATCH 010/113] Concretize documentation of route segments Signed-off-by: Fabian Pfeuffer --- osi_route.proto | 29 ++++++++++++++++++++++------- 1 file changed, 22 insertions(+), 7 deletions(-) diff --git a/osi_route.proto b/osi_route.proto index 147c66f14..54afc6dc8 100644 --- a/osi_route.proto +++ b/osi_route.proto @@ -53,6 +53,13 @@ message Route // // \brief A segment of a logical lane. // + // \note The #LogicalLaneSegment allows that #start_s > #end_s. + // If #start_s < #end_s, then the traffic agent should traverse the + // segment in the logical lane's reference line definition direction. + // If #end_s > #start_s, then the traffic agent should traverse the + // segment in the opposite of the logical lane's reference line + // definition direction. + // message LogicalLaneSegment { // The ID of the logical lane this segment belongs to. @@ -76,15 +83,23 @@ message Route // \brief A segment of a route. // // A route segment describes a segment of a traffic agent's route through the - // road network. The route segment is composed of a list of logical lanes - // segments that indicate the agent which logical lanes it should use in a - // given interval, so that it will eventually reach its destination. - // In general, only lanes should be listed that are parallel to each - // other, though some may have different lengths (e.g. if a lane widening + // logical lanes of the road network. + // + // Each time there is a successor-predecessor relation between the logical + // lanes along the route (i.e. a logical lane ends, and is continued by another + // logical lane, e.g. at a junction border), a new #RouteSegment starts. The + // #RouteSegment then lists the logical lane segments that can be used to + // travel through this space of the road. + // + // Together, the listed logical lane segments should form a continuous area, + // where the traffic agent can move freely. These will mostly be parallel + // lanes, though lanes may overlap (e.g. if one lane splits into two on a + // junction). In general, the logical lane segments in a #RouteSegment will + // have the same length, though there are exceptions (e.g. if a lane widening // occurs, the newly appearing lane will have a shorter length). // // Typically a route segment will be either - // - a set of lanes between two junctions, or + // - a set of parallel lanes between two junctions, or // - parallel lanes on an intersection with the same driving direction // // ## Example @@ -113,7 +128,7 @@ message Route // // The logical lane segments of a route segment should be connected without // gaps, meaning that, together, the lane segments should form a - // continous area. + // continuous area. // repeated LogicalLaneSegment lane_segment = 1; From fbe6362855fa2c466b114bb6a6bc6e10d6a65ed6 Mon Sep 17 00:00:00 2001 From: "Pierre R. Mai" Date: Mon, 15 Jan 2024 16:27:39 +0100 Subject: [PATCH 011/113] Fix proto syntax and formatting Signed-off-by: Pierre R. Mai --- osi_route.proto | 32 ++++++++++++++------------------ setup.py | 2 +- 2 files changed, 15 insertions(+), 19 deletions(-) diff --git a/osi_route.proto b/osi_route.proto index 54afc6dc8..b7e519330 100644 --- a/osi_route.proto +++ b/osi_route.proto @@ -1,4 +1,4 @@ -syntax = "proto3"; +syntax = "proto2"; option optimize_for = SPEED; @@ -33,7 +33,6 @@ package osi3; // message Route { - // The unique id of the route. // // \note This field is mandatory. @@ -53,12 +52,12 @@ message Route // // \brief A segment of a logical lane. // - // \note The #LogicalLaneSegment allows that #start_s > #end_s. - // If #start_s < #end_s, then the traffic agent should traverse the - // segment in the logical lane's reference line definition direction. - // If #end_s > #start_s, then the traffic agent should traverse the - // segment in the opposite of the logical lane's reference line - // definition direction. + // \note The LogicalLaneSegment allows that start_s > end_s. + // If start_s < end_s, then the traffic agent should traverse the + // segment in the logical lane's reference line definition direction. + // If end_s > start_s, then the traffic agent should traverse the + // segment in the opposite of the logical lane's reference line + // definition direction. // message LogicalLaneSegment { @@ -87,16 +86,16 @@ message Route // // Each time there is a successor-predecessor relation between the logical // lanes along the route (i.e. a logical lane ends, and is continued by another - // logical lane, e.g. at a junction border), a new #RouteSegment starts. The - // #RouteSegment then lists the logical lane segments that can be used to + // logical lane, e.g. at a junction border), a new RouteSegment starts. The + // RouteSegment then lists the logical lane segments that can be used to // travel through this space of the road. // // Together, the listed logical lane segments should form a continuous area, // where the traffic agent can move freely. These will mostly be parallel // lanes, though lanes may overlap (e.g. if one lane splits into two on a - // junction). In general, the logical lane segments in a #RouteSegment will - // have the same length, though there are exceptions (e.g. if a lane widening - // occurs, the newly appearing lane will have a shorter length). + // junction). In general, the logical lane segments in a RouteSegment will + // have the same length, though there are exceptions (e.g. if a lane + // widening occurs, the newly appearing lane will have a shorter length). // // Typically a route segment will be either // - a set of parallel lanes between two junctions, or @@ -127,12 +126,9 @@ message Route // Logical lane segments that form a route segment. // // The logical lane segments of a route segment should be connected without - // gaps, meaning that, together, the lane segments should form a - // continuous area. + // gaps, meaning that, together, the lane segments should form a continuous + // area. // repeated LogicalLaneSegment lane_segment = 1; - } - - } diff --git a/setup.py b/setup.py index b09aee6c3..cad557993 100644 --- a/setup.py +++ b/setup.py @@ -73,7 +73,7 @@ def find_protoc(): "osi_occupant.proto", "osi_referenceline.proto", "osi_roadmarking.proto", - 'osi_route.proto', + "osi_route.proto", "osi_sensordata.proto", "osi_sensorspecific.proto", "osi_sensorview.proto", From e1a9978647fced837025e4e2efeb04a598f79001 Mon Sep 17 00:00:00 2001 From: ClemensLinnhoff Date: Wed, 13 Dec 2023 09:12:35 +0100 Subject: [PATCH 012/113] Add orientation rate to PedestrianAttributes::Bone Signed-off-by: ClemensLinnhoff --- osi_object.proto | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/osi_object.proto b/osi_object.proto index 9d802b680..3cf20e426 100644 --- a/osi_object.proto +++ b/osi_object.proto @@ -1172,6 +1172,10 @@ message MovingObject // optional bool missing = 5; + // The orientation rate of the bone. + // + optional Orientation3d orientation_rate = 6; + // The type of the bone. // // \image html OSI_PedestrianModelHierarchy.jpg From e0d86d3661544b2f285326ff55f0f1b96ef36315 Mon Sep 17 00:00:00 2001 From: ClemensLinnhoff Date: Tue, 30 Jan 2024 11:54:03 +0100 Subject: [PATCH 013/113] Add velocity Signed-off-by: ClemensLinnhoff --- osi_object.proto | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/osi_object.proto b/osi_object.proto index 3cf20e426..e6108465f 100644 --- a/osi_object.proto +++ b/osi_object.proto @@ -1172,9 +1172,16 @@ message MovingObject // optional bool missing = 5; + // The velocity of the bone. + // + // Reference System is the root, defined by bbcenter_to_root + // (\c PedestrianAttributes::bbcenter_to_root). + // + optional Vector3d velocity = 6; + // The orientation rate of the bone. // - optional Orientation3d orientation_rate = 6; + optional Orientation3d orientation_rate = 7; // The type of the bone. // From 19bc76bed17e4f6a5167ffdb37b32e159eaf6e04 Mon Sep 17 00:00:00 2001 From: ClemensLinnhoff Date: Tue, 30 Jan 2024 11:54:28 +0100 Subject: [PATCH 014/113] Add reference system to orientation rate Signed-off-by: ClemensLinnhoff --- osi_object.proto | 3 +++ 1 file changed, 3 insertions(+) diff --git a/osi_object.proto b/osi_object.proto index e6108465f..3868eb3ff 100644 --- a/osi_object.proto +++ b/osi_object.proto @@ -1181,6 +1181,9 @@ message MovingObject // The orientation rate of the bone. // + // Reference System is the root, defined by bbcenter_to_root + // (\c PedestrianAttributes::bbcenter_to_root). + // optional Orientation3d orientation_rate = 7; // The type of the bone. From 8b5537fca4772d724d9758f40898b99ac3915bbf Mon Sep 17 00:00:00 2001 From: ClemensLinnhoff Date: Wed, 14 Feb 2024 18:14:55 +0100 Subject: [PATCH 015/113] Add is_set as to rules.yml Signed-off-by: ClemensLinnhoff --- rules.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/rules.yml b/rules.yml index 473bf51b2..1816a7542 100644 --- a/rules.yml +++ b/rules.yml @@ -9,4 +9,5 @@ refers_to: '^[ ]\b(refers_to)\b' is_iso_country_code: '^[ ]\b(is_iso_country_code)\b' first_element: '^[ ]\b(first_element)\b' last_element: '^[ ]\b(last_element)\b' -check_if: '^[ ](\bcheck_if\b)(.*\belse do_check\b)' \ No newline at end of file +check_if: '^[ ](\bcheck_if\b)(.*\belse do_check\b)' +is_set: '^[ ]\b(is_set)\b' \ No newline at end of file From 0b4a95a35190446761e7a3e044da4197c1b96513 Mon Sep 17 00:00:00 2001 From: ClemensLinnhoff Date: Wed, 14 Feb 2024 18:35:12 +0100 Subject: [PATCH 016/113] Set of proposed mandatory fields Signed-off-by: ClemensLinnhoff --- osi_detectedobject.proto | 4 ++++ osi_featuredata.proto | 8 ++++++++ osi_groundtruth.proto | 8 ++++++++ osi_lane.proto | 1 + osi_logicaldetectiondata.proto | 4 ++++ osi_logicallane.proto | 1 + osi_motionrequest.proto | 8 ++++++++ osi_object.proto | 2 ++ osi_referenceline.proto | 1 + osi_roadmarking.proto | 4 ++++ osi_route.proto | 4 ++++ osi_sensordata.proto | 20 ++++++++++++++++++++ osi_sensorview.proto | 14 ++++++++++++++ osi_sensorviewconfiguration.proto | 8 ++++++++ osi_streamingupdate.proto | 8 ++++++++ osi_trafficcommand.proto | 12 ++++++++++++ osi_trafficcommandupdate.proto | 12 ++++++++++++ osi_trafficlight.proto | 1 + osi_trafficsign.proto | 1 + osi_trafficupdate.proto | 8 ++++++++ 20 files changed, 129 insertions(+) diff --git a/osi_detectedobject.proto b/osi_detectedobject.proto index d651b949e..030747f06 100644 --- a/osi_detectedobject.proto +++ b/osi_detectedobject.proto @@ -17,6 +17,10 @@ message DetectedItemHeader // Specific ID of the detected item as assigned by the sensor internally. // Needs not to match with \c #ground_truth_id. // + // \rules + // is_set + // \endrules + // optional Identifier tracking_id = 1; // The ID of the original detected item in the ground truth. diff --git a/osi_featuredata.proto b/osi_featuredata.proto index 16ed85aaf..69b4fcd62 100644 --- a/osi_featuredata.proto +++ b/osi_featuredata.proto @@ -92,6 +92,10 @@ message SensorDetectionHeader // \par Reference: // [1] DIN Deutsches Institut fuer Normung e. V. (2013). DIN ISO 8855 Strassenfahrzeuge - Fahrzeugdynamik und Fahrverhalten - Begriffe. (DIN ISO 8855:2013-11). Berlin, Germany. // + // \rules + // is_set + // \endrules + // optional MountingPosition mounting_position = 3; // The origin/orientation of the sensor frame represents the current @@ -124,6 +128,10 @@ message SensorDetectionHeader // This ID can equal \c SensorData::sensor_id, if \c SensorData holds only // data from one sensor/sensor model. // + // \rules + // is_set + // \endrules + // optional Identifier sensor_id = 7; // The extended qualifier describes the reason (not the effect) why the diff --git a/osi_groundtruth.proto b/osi_groundtruth.proto index 5cf5477b5..cb5997465 100644 --- a/osi_groundtruth.proto +++ b/osi_groundtruth.proto @@ -47,6 +47,10 @@ message GroundTruth // The interface version used by the sender (i.e. the simulation // environment). // + // \rules + // is_set + // \endrules + // optional InterfaceVersion version = 1; // The data timestamp of the simulation environment. The zero time point is @@ -60,6 +64,10 @@ message GroundTruth // (there is no inherent latency for ground truth data, as opposed to // sensor data). // + // \rules + // is_set + // \endrules + // optional Timestamp timestamp = 2; // The ID of the host vehicle object referencing to \c MovingObject . diff --git a/osi_lane.proto b/osi_lane.proto index c95a30de1..702a088d9 100644 --- a/osi_lane.proto +++ b/osi_lane.proto @@ -42,6 +42,7 @@ message Lane // // \rules // is_globally_unique + // is_set // \endrules // optional Identifier id = 1; diff --git a/osi_logicaldetectiondata.proto b/osi_logicaldetectiondata.proto index cbf0e71fe..353abd407 100644 --- a/osi_logicaldetectiondata.proto +++ b/osi_logicaldetectiondata.proto @@ -19,6 +19,10 @@ message LogicalDetectionData // The interface version used by the sender (i.e. the simulation // environment). // + // \rules + // is_set + // \endrules + // optional InterfaceVersion version = 1; // Header attributes of fused detections from multiple sensors and sensor types. diff --git a/osi_logicallane.proto b/osi_logicallane.proto index f709a89a6..5d3828673 100644 --- a/osi_logicallane.proto +++ b/osi_logicallane.proto @@ -56,6 +56,7 @@ message LogicalLaneBoundary // // \rules // is_globally_unique + // is_set // \endrules // optional Identifier id = 1; diff --git a/osi_motionrequest.proto b/osi_motionrequest.proto index 82560c8e6..be81b0804 100644 --- a/osi_motionrequest.proto +++ b/osi_motionrequest.proto @@ -25,11 +25,19 @@ message MotionRequest { // The interface version used by the sender (simulation environment). // + // \rules + // is_set + // \endrules + // optional InterfaceVersion version = 1; // The data timestamp of the simulation environment. // A reference to \c Timestamp message. // + // \rules + // is_set + // \endrules + // optional Timestamp timestamp = 2; // Define the type that is used to specify the motion request. diff --git a/osi_object.proto b/osi_object.proto index 3868eb3ff..fa879188a 100644 --- a/osi_object.proto +++ b/osi_object.proto @@ -21,6 +21,7 @@ message StationaryObject // // \rules // is_globally_unique + // is_set // \endrules // optional Identifier id = 1; @@ -388,6 +389,7 @@ message MovingObject // // \rules // is_globally_unique + // is_set // \endrules // optional Identifier id = 1; diff --git a/osi_referenceline.proto b/osi_referenceline.proto index b6b3bc5e4..72fa312a8 100644 --- a/osi_referenceline.proto +++ b/osi_referenceline.proto @@ -32,6 +32,7 @@ message ReferenceLine // // \rules // is_globally_unique + // is_set // \endrules // optional Identifier id = 1; diff --git a/osi_roadmarking.proto b/osi_roadmarking.proto index d8ed5a2e0..f002f9bb5 100644 --- a/osi_roadmarking.proto +++ b/osi_roadmarking.proto @@ -29,6 +29,10 @@ message RoadMarking { // The ID of the road marking. // + // \rules + // is_set + // \endrules + // optional Identifier id = 1; // The base parameters of the road marking. diff --git a/osi_route.proto b/osi_route.proto index b7e519330..794c6bb20 100644 --- a/osi_route.proto +++ b/osi_route.proto @@ -40,6 +40,10 @@ message Route // \note This id must be unique within all route messages exchanged with // one traffic participant. // + // \rules + // is_set + // \endrules + // optional Identifier route_id = 1; // Route segments that form the route of an agent. diff --git a/osi_sensordata.proto b/osi_sensordata.proto index 689149370..0d4a2ac21 100644 --- a/osi_sensordata.proto +++ b/osi_sensordata.proto @@ -102,6 +102,10 @@ message SensorData { // The interface version used by the sender. // + // \rules + // is_set + // \endrules + // optional InterfaceVersion version = 1; // The timestamp of the sensor data. Zero time is arbitrary but must be @@ -129,6 +133,10 @@ message SensorData // a dumb sensor with no internal time concept), the two timestamps might // also be identical, but delayed from the \c GroundTruth timestamp. // + // \rules + // is_set + // \endrules + // optional Timestamp timestamp = 2; // The sensors estimated location of the host vehicle @@ -138,6 +146,10 @@ message SensorData // \note Note that dimension and base_polygon need not be set. // \note The parent frame of \c host_vehicle_location is the sensor frame. // + // \rules + // is_set + // \endrules + // optional BaseMoving host_vehicle_location = 3; // The sensors estimated location error of the host vehicle @@ -156,6 +168,10 @@ message SensorData // object output; it is distinct from the IDs of its physical detectors, // which are used in the detected features. // + // \rules + // is_set + // \endrules + // optional Identifier sensor_id = 5; // The virtual mounting position of the sensor (origin and orientation @@ -186,6 +202,10 @@ message SensorData // vehicle's bounding box \c MovingObject::base . \c // BaseMoving::orientation. // + // \rules + // is_set + // \endrules + // optional MountingPosition mounting_position = 6; // The root mean squared error of the mounting position. diff --git a/osi_sensorview.proto b/osi_sensorview.proto index 8d595ed92..863a5c2bb 100644 --- a/osi_sensorview.proto +++ b/osi_sensorview.proto @@ -36,6 +36,10 @@ message SensorView { // The interface version used by the sender (simulation environment). // + // \rules + // is_set + // \endrules + // optional InterfaceVersion version = 1; // The data timestamp of the simulation environment. Zero time is arbitrary @@ -48,6 +52,10 @@ message SensorView // (there is no inherent latency for sensor view data, as opposed to // sensor data). // + // \rules + // is_set + // \endrules + // optional Timestamp timestamp = 2; // The ID of the sensor at host vehicle's \c #mounting_position. @@ -58,6 +66,7 @@ message SensorView // // \rules // is_globally_unique + // is_set // \endrules // optional Identifier sensor_id = 3; @@ -92,6 +101,10 @@ message SensorView // vehicle's bounding box \c MovingObject::base . \c // BaseMoving::orientation. // + // \rules + // is_set + // \endrules + // optional MountingPosition mounting_position = 4; // The root mean squared error of the mounting position. @@ -127,6 +140,7 @@ message SensorView // // \rules // refers_to: 'MovingObject' + // is_set // \endrules // optional Identifier host_vehicle_id = 8; diff --git a/osi_sensorviewconfiguration.proto b/osi_sensorviewconfiguration.proto index fc3720ebc..1419c9312 100644 --- a/osi_sensorviewconfiguration.proto +++ b/osi_sensorviewconfiguration.proto @@ -66,6 +66,10 @@ message SensorViewConfiguration { // The interface version used by the sender (simulation environment). // + // \rules + // is_set + // \endrules + // optional InterfaceVersion version = 1; // The ID of the sensor at host vehicle's mounting_position. @@ -77,6 +81,10 @@ message SensorViewConfiguration // The ID is to be provided by the environment simulation, the sensor // model is not in a position to provide a useful default value. // + // \rules + // is_set + // \endrules + // optional Identifier sensor_id = 2; // The virtual mounting position of the sensor (origin and orientation diff --git a/osi_streamingupdate.proto b/osi_streamingupdate.proto index b1ad1121a..f3006fee9 100644 --- a/osi_streamingupdate.proto +++ b/osi_streamingupdate.proto @@ -30,6 +30,10 @@ message StreamingUpdate { // The interface version used by the sender. // + // \rules + // is_set + // \endrules + // optional InterfaceVersion version = 1; // The data timestamp where the information of contained objects is calculated. @@ -38,6 +42,10 @@ message StreamingUpdate // Zero time does not need to coincide with the UNIX epoch. // Recommended is the starting time point of the simulation. // + // \rules + // is_set + // \endrules + // optional Timestamp timestamp = 2; // The list of stationary objects (excluding traffic signs and traffic diff --git a/osi_trafficcommand.proto b/osi_trafficcommand.proto index 6e717e3e8..5baef7731 100644 --- a/osi_trafficcommand.proto +++ b/osi_trafficcommand.proto @@ -21,6 +21,10 @@ message TrafficCommand { // The interface version used by the sender (scenario engine). // + // \rules + // is_set + // \endrules + // optional InterfaceVersion version = 1; // The data timestamp of the simulation environment. Zero time is arbitrary @@ -33,10 +37,18 @@ message TrafficCommand // There is no inherent latency for traffic command data, as opposed // to sensor data. // + // \rules + // is_set + // \endrules + // optional Timestamp timestamp = 2; // The ID of this traffic participant. // + // \rules + // is_set + // \endrules + // optional Identifier traffic_participant_id = 3; // Commanded traffic action(s) if any. diff --git a/osi_trafficcommandupdate.proto b/osi_trafficcommandupdate.proto index d55d38ff3..c341acfdc 100644 --- a/osi_trafficcommandupdate.proto +++ b/osi_trafficcommandupdate.proto @@ -29,6 +29,10 @@ message TrafficCommandUpdate { // The interface version used by the sender (traffic participant model). // + // \rules + // is_set + // \endrules + // optional InterfaceVersion version = 1; // The data timestamp of the simulation environment. Zero time is arbitrary @@ -36,11 +40,19 @@ message TrafficCommandUpdate // coincide with the UNIX epoch. It is recommended to use zero timestamp as // the starting time point of the simulation. // + // \rules + // is_set + // \endrules + // optional Timestamp timestamp = 2; // The ID of this traffic participant which must coincide with a prior sent ID, cf. // \c TrafficCommand::traffic_participant_id. // + // \rules + // is_set + // \endrules + // optional Identifier traffic_participant_id = 3; // Actions which a traffic participant dismisses and which are not yet ended or diff --git a/osi_trafficlight.proto b/osi_trafficlight.proto index 887a99fd4..fe90fd4b4 100644 --- a/osi_trafficlight.proto +++ b/osi_trafficlight.proto @@ -20,6 +20,7 @@ message TrafficLight // // \rules // is_globally_unique + // is_set // \endrules // optional Identifier id = 1; diff --git a/osi_trafficsign.proto b/osi_trafficsign.proto index f15aad856..11e600d4d 100644 --- a/osi_trafficsign.proto +++ b/osi_trafficsign.proto @@ -173,6 +173,7 @@ message TrafficSign // // \rules // is_globally_unique + // is_set // \endrules // optional Identifier id = 1; diff --git a/osi_trafficupdate.proto b/osi_trafficupdate.proto index 5b157c668..45a87d6fb 100644 --- a/osi_trafficupdate.proto +++ b/osi_trafficupdate.proto @@ -27,6 +27,10 @@ message TrafficUpdate { // The interface version used by the sender (traffic participant model). // + // \rules + // is_set + // \endrules + // optional InterfaceVersion version = 1; // The data timestamp of the simulation environment. Zero time is arbitrary @@ -39,6 +43,10 @@ message TrafficUpdate // There is no inherent latency for moving object update data, as opposed // to sensor data. // + // \rules + // is_set + // \endrules + // optional Timestamp timestamp = 2; // Updated traffic participant data From b1db3d4cdbfd2ee5061fb1e646f20180eb2bf2aa Mon Sep 17 00:00:00 2001 From: ClemensLinnhoff Date: Wed, 14 Feb 2024 18:38:49 +0100 Subject: [PATCH 017/113] Remove host_vehicle_location Signed-off-by: ClemensLinnhoff --- osi_groundtruth.proto | 1 + osi_sensordata.proto | 4 ---- 2 files changed, 1 insertion(+), 4 deletions(-) diff --git a/osi_groundtruth.proto b/osi_groundtruth.proto index cb5997465..4fd172aca 100644 --- a/osi_groundtruth.proto +++ b/osi_groundtruth.proto @@ -76,6 +76,7 @@ message GroundTruth // // \rules // refers_to: MovingObject + // is_set // \endrules // optional Identifier host_vehicle_id = 3; diff --git a/osi_sensordata.proto b/osi_sensordata.proto index 0d4a2ac21..523cb4cfb 100644 --- a/osi_sensordata.proto +++ b/osi_sensordata.proto @@ -146,10 +146,6 @@ message SensorData // \note Note that dimension and base_polygon need not be set. // \note The parent frame of \c host_vehicle_location is the sensor frame. // - // \rules - // is_set - // \endrules - // optional BaseMoving host_vehicle_location = 3; // The sensors estimated location error of the host vehicle From 3b52cb63dcd838cea4e23b83e98ad12deda6cddc Mon Sep 17 00:00:00 2001 From: ClemensLinnhoff Date: Wed, 14 Feb 2024 18:44:05 +0100 Subject: [PATCH 018/113] Adjust documentation Signed-off-by: ClemensLinnhoff --- doc/architecture/architecture_overview.adoc | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/doc/architecture/architecture_overview.adoc b/doc/architecture/architecture_overview.adoc index 6ef5b76ee..9d8a20228 100644 --- a/doc/architecture/architecture_overview.adoc +++ b/doc/architecture/architecture_overview.adoc @@ -51,7 +51,8 @@ This has been done to allow backward-compatible changes in the field. Additionally, this is the default behavior in Protocol Buffer version 3 that no longer has the `required` type. Setting all fields to `optional` thus ensures update compatibility. However, this does not mean that it is optional to fill the field. -For the purpose of providing a complete interface, all existing fields should be set, unless not setting a field carries a specific meaning, as indicated in the accompanying comment. +Fields with the rule `is_set` are mandatory and have to be set at all times. +All other fields have to be set according to the requirements of the connected models. NOTE: All field numbers equal to or greater than 10000 are available for user-specific extensions via custom fields. No future evolution of OSI will therefore use field numbers equal to or greater than 10000. From a6e0aa564c9249523670627f9eb26c720f2fe3d9 Mon Sep 17 00:00:00 2001 From: ClemensLinnhoff Date: Wed, 21 Feb 2024 11:07:04 +0100 Subject: [PATCH 019/113] Remove : from country code rule Signed-off-by: ClemensLinnhoff --- osi_groundtruth.proto | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osi_groundtruth.proto b/osi_groundtruth.proto index 4fd172aca..651ff7e81 100644 --- a/osi_groundtruth.proto +++ b/osi_groundtruth.proto @@ -127,7 +127,7 @@ message GroundTruth // [1] ISO International Organization for Standardization. (2013). ISO 3166-1 Codes for the representation of names of countries and their subdivisions - Part 1: Country codes. (ISO 3166-1:2013). Geneva, Switzerland. // // \rules - // is_iso_country_code: + // is_iso_country_code // \endrules // optional uint32 country_code = 13; From 1f22ae2d9caf0ddab61e20f98088ed18225cadbc Mon Sep 17 00:00:00 2001 From: Philipp Rosenberger Date: Wed, 14 Feb 2024 17:58:09 +0100 Subject: [PATCH 020/113] Removal of the historical .txt trace file format and related scripts Signed-off-by: Philipp Rosenberger --- doc/architecture/formatting_scripts.adoc | 22 ------ doc/architecture/trace_file_formats.adoc | 6 +- format/osi2read.py | 5 +- format/txt2osi.py | 88 ------------------------ 4 files changed, 3 insertions(+), 118 deletions(-) delete mode 100644 format/txt2osi.py diff --git a/doc/architecture/formatting_scripts.adoc b/doc/architecture/formatting_scripts.adoc index 9b1a26857..a953b3e13 100644 --- a/doc/architecture/formatting_scripts.adoc +++ b/doc/architecture/formatting_scripts.adoc @@ -7,28 +7,6 @@ endif::[] The OSI repository contains Python scripts for converting trace files from one format to another. The formatting scripts are stored in `open-simulation-interface/format/` -**txt2osi.py** - -`txt2osi.py` converts plain-text trace files to binary `.osi` trace files. -This script takes the following parameters: - -`--data`, `-d`:: -String containing the path to the file with serialized data. - -`--type`, `-t`:: -Optional string describing the message type used to serialize data. -`'SensorView'`, `'GroundTruth'`, or `'SensorData'` are permitted values. -The default value is `'SensorView'`. - -`--output`, `-o`:: -Optional string containing the name of the output file. -The default value is `'converted.osi'`. - -`--compress`, `-c`:: -Optional Boolean controlling whether to compress the output to an lzma file. -`True`, or `False` are permitted values. -The default value is `False`. - **osi2read.py** `osi2read.py` converts trace files to human-readable `.txth` trace files. diff --git a/doc/architecture/trace_file_formats.adoc b/doc/architecture/trace_file_formats.adoc index 0ed0a4515..c0e929f00 100644 --- a/doc/architecture/trace_file_formats.adoc +++ b/doc/architecture/trace_file_formats.adoc @@ -5,7 +5,7 @@ endif::[] [#top-osi_trace_file_formats] = OSI trace file formats -There are multiple formats for storing multiple serialized OSI messages in one trace file. +There are two formats for storing multiple serialized OSI messages in one trace file. *.osi:: Binary trace file. @@ -13,10 +13,6 @@ Messages are separated by a length specification before each message. The length is represented by a four-byte, little-endian, unsigned integer. The length does not include the integer itself. -*.txt:: -Plain-text trace file. -Messages are separated by `$$__$$`. - *.txth:: Human-readable plain-text trace file. Messages are separated by newlines. diff --git a/format/osi2read.py b/format/osi2read.py index 90eb88a4d..d583d8253 100644 --- a/format/osi2read.py +++ b/format/osi2read.py @@ -1,9 +1,8 @@ """ -This program converts serialized txt/osi trace files into a human readable txth file. +This program converts serialized osi trace files into a human readable txth file. Example usage: python3 osi2read.py -d trace.osi -o myreadableosifile - python3 osi2read.py -d trace.txt -f separated -o myreadableosifile """ from OSITrace import OSITrace @@ -19,7 +18,7 @@ def command_line_arguments(): dir_path = os.path.dirname(os.path.dirname(os.path.realpath(__file__))) parser = argparse.ArgumentParser( - description="Convert a serialized osi/txt trace file to a readable txth output.", + description="Convert a serialized osi trace file to a readable txth output.", prog="osi2read converter", ) parser.add_argument( diff --git a/format/txt2osi.py b/format/txt2osi.py deleted file mode 100644 index 13eb8e788..000000000 --- a/format/txt2osi.py +++ /dev/null @@ -1,88 +0,0 @@ -""" -This program converts txt trace files separated with $$__$$ to OSI trace files which are defined by the length of each OSI message. - -Example usage: - python3 txt2osi.py -d trace.txt - python3 txt2osi.py -d trace.txt -o myfile - python3 txt2osi.py -d trace.txt -o myfile -c - python3 txt2osi.py -d trace.txt.lzma -c - python3 txt2osi.py -d trace.txt.lzma -""" - -from OSITrace import OSITrace -import struct -import lzma -import argparse -import os - - -def command_line_arguments(): - """Define and handle command line interface""" - - dir_path = os.path.dirname(os.path.dirname(os.path.realpath(__file__))) - - parser = argparse.ArgumentParser( - description="Convert txt trace file to osi trace files.", - prog="txt2osi converter", - ) - parser.add_argument( - "--data", "-d", help="Path to the file with serialized data.", type=str - ) - parser.add_argument( - "--type", - "-t", - help="Name of the type used to serialize data.", - choices=["SensorView", "GroundTruth", "SensorData"], - default="SensorView", - type=str, - required=False, - ) - parser.add_argument( - "--output", - "-o", - help="Output name of the file.", - default="converted.osi", - type=str, - required=False, - ) - parser.add_argument( - "--compress", - "-c", - help="Compress the output to a lzma file.", - default=False, - required=False, - action="store_true", - ) - - return parser.parse_args() - - -def main(): - # Handling of command line arguments - args = command_line_arguments() - - # Initialize the OSI trace class - trace = OSITrace() - trace.from_file(path=args.data, type_name=args.type, format_type="separated") - sv = trace.get_messages() # Create an iterator for messages - - args.output = args.output.split(".", 1)[0] + ".osi" - - if args.output == "converted.osi": - args.output = args.data.split(".", 1)[0] + ".osi" - - if args.compress: - f = lzma.open(args.output + ".lzma", "ab") - else: - f = open(args.output, "ab") - - for message in sv: - byte_buffer = message.SerializeToString() - f.write(struct.pack(" Date: Mon, 19 Feb 2024 16:26:39 +0100 Subject: [PATCH 021/113] removing format command line argument and associated functions Signed-off-by: Philipp Rosenberger --- format/OSITrace.py | 116 +++++++-------------------------------------- format/osi2read.py | 9 ---- 2 files changed, 16 insertions(+), 109 deletions(-) diff --git a/format/OSITrace.py b/format/OSITrace.py index d8d2c246a..ed7db1a4b 100644 --- a/format/OSITrace.py +++ b/format/OSITrace.py @@ -13,8 +13,6 @@ warnings.simplefilter("default") -SEPARATOR = b"$$__$$" -SEPARATOR_LENGTH = len(SEPARATOR) BUFFER_SIZE = 1000000 @@ -47,7 +45,7 @@ def __init__(self, path=None, type_name="SensorView"): self.retrieved_scenario_size = 0 self._int_length = len(struct.pack("= scenario_size: - break - self.message_offsets.append(message_offset) - - if eof: - self.retrieved_scenario_size = scenario_size - else: - self.retrieved_scenario_size = self.message_offsets[-1] - self.message_offsets.pop() - - return len(self.message_offsets) + self.timestep_count = self.retrieve_message() def retrieve_message(self): scenario_size = get_size_from_file_stream(self.scenario_file) @@ -180,42 +117,21 @@ def get_messages_in_index_range(self, begin, end): for abs_message_offset in self.message_offsets[begin:end] ] - if self.format_type == "separated": - message_sequence_len = abs_last_offset - abs_first_offset - SEPARATOR_LENGTH - serialized_messages_extract = self.scenario_file.read(message_sequence_len) - - for rel_index, rel_message_offset in enumerate(rel_message_offsets): - rel_begin = rel_message_offset - rel_end = ( - rel_message_offsets[rel_index + 1] - SEPARATOR_LENGTH - if rel_index + 1 < len(rel_message_offsets) - else message_sequence_len - ) - message = MESSAGES_TYPE[self.type_name]() - serialized_message = serialized_messages_extract[rel_begin:rel_end] - message.ParseFromString(serialized_message) - yield message - - elif self.format_type is None: - message_sequence_len = abs_last_offset - abs_first_offset - serialized_messages_extract = self.scenario_file.read(message_sequence_len) - - for rel_index, rel_message_offset in enumerate(rel_message_offsets): - rel_begin = rel_message_offset + self._int_length - rel_end = ( - rel_message_offsets[rel_index + 1] - if rel_index + 1 < len(rel_message_offsets) - else message_sequence_len - ) - - message = MESSAGES_TYPE[self.type_name]() - serialized_message = serialized_messages_extract[rel_begin:rel_end] - message.ParseFromString(serialized_message) - yield message + message_sequence_len = abs_last_offset - abs_first_offset + serialized_messages_extract = self.scenario_file.read(message_sequence_len) - else: - self.scenario_file.close() - raise Exception(f"The defined format {self.format_type} does not exist.") + for rel_index, rel_message_offset in enumerate(rel_message_offsets): + rel_begin = rel_message_offset + self._int_length + rel_end = ( + rel_message_offsets[rel_index + 1] + if rel_index + 1 < len(rel_message_offsets) + else message_sequence_len + ) + + message = MESSAGES_TYPE[self.type_name]() + serialized_message = serialized_messages_extract[rel_begin:rel_end] + message.ParseFromString(serialized_message) + yield message def make_readable(self, name, interval=None, index=None): self.scenario_file.seek(0) diff --git a/format/osi2read.py b/format/osi2read.py index d583d8253..1f828e36b 100644 --- a/format/osi2read.py +++ b/format/osi2read.py @@ -41,15 +41,6 @@ def command_line_arguments(): type=str, required=False, ) - parser.add_argument( - "--format", - "-f", - help="Set the format type of the trace.", - choices=["separated", None], - default=None, - type=str, - required=False, - ) return parser.parse_args() From b86013e7b17f680928994911ed283684abb27ef8 Mon Sep 17 00:00:00 2001 From: Philipp Rosenberger Date: Mon, 19 Feb 2024 16:45:56 +0100 Subject: [PATCH 022/113] removing 1 more format option Signed-off-by: Philipp Rosenberger --- format/OSITrace.py | 1 - 1 file changed, 1 deletion(-) diff --git a/format/OSITrace.py b/format/OSITrace.py index ed7db1a4b..cc92f06c7 100644 --- a/format/OSITrace.py +++ b/format/OSITrace.py @@ -54,7 +54,6 @@ def from_file(self, path, type_name="SensorView", max_index=-1): self.scenario_file = open(path, "rb") self.type_name = type_name - self.format_type = format_type self.timestep_count = self.retrieve_message() def retrieve_message(self): From 85d8f50454646c84566d80175bddf6296e7a31fb Mon Sep 17 00:00:00 2001 From: Thomas Sedlmayer Date: Mon, 26 Feb 2024 11:04:22 +0100 Subject: [PATCH 023/113] Remove format_type arg from function call Signed-off-by: Thomas Sedlmayer --- format/osi2read.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/format/osi2read.py b/format/osi2read.py index 1f828e36b..240507177 100644 --- a/format/osi2read.py +++ b/format/osi2read.py @@ -51,7 +51,7 @@ def main(): # Initialize the OSI trace class trace = OSITrace() - trace.from_file(path=args.data, type_name=args.type, format_type=args.format) + trace.from_file(path=args.data, type_name=args.type) args.output = args.output.split(".", 1)[0] + ".txth" From f38c9221c27342cbda7594710fb4edb402fbbcd4 Mon Sep 17 00:00:00 2001 From: "Pierre R. Mai" Date: Mon, 26 Feb 2024 11:52:17 +0100 Subject: [PATCH 024/113] Add historical note of txt format Signed-off-by: Pierre R. Mai --- doc/architecture/trace_file_formats.adoc | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/doc/architecture/trace_file_formats.adoc b/doc/architecture/trace_file_formats.adoc index c0e929f00..60f2d2a4b 100644 --- a/doc/architecture/trace_file_formats.adoc +++ b/doc/architecture/trace_file_formats.adoc @@ -16,4 +16,9 @@ The length does not include the integer itself. *.txth:: Human-readable plain-text trace file. Messages are separated by newlines. + +NOTE: Previous releases of OSI also supported a so-called plain-text trace file format, with file extension `.txt`. +This legacy format did not contain plain-text, but rather binary protobuf messages separated by a special separator. +For obvious reasons the format was deprecated and fully replaced with the `.osi` binary file format. +This release no longer contains any support for the legacy `.txt` file format. These files may be used for manual checks. From 9a5786aa88f9eba20f6bb0ee04f0cf220c8a0b08 Mon Sep 17 00:00:00 2001 From: ClemensLinnhoff Date: Mon, 12 Feb 2024 16:23:23 +0100 Subject: [PATCH 025/113] Fix typos in proto files Signed-off-by: ClemensLinnhoff --- osi_common.proto | 6 +++--- osi_detectedobject.proto | 4 ++-- osi_featuredata.proto | 18 +++++++++--------- osi_hostvehicledata.proto | 2 +- osi_lane.proto | 8 ++++---- osi_logicallane.proto | 10 +++++----- osi_object.proto | 8 ++++---- osi_referenceline.proto | 2 +- osi_sensorview.proto | 4 ++-- osi_streamingupdate.proto | 2 +- osi_trafficcommand.proto | 22 +++++++++++----------- osi_trafficlight.proto | 2 +- osi_trafficupdate.proto | 2 +- 13 files changed, 45 insertions(+), 45 deletions(-) diff --git a/osi_common.proto b/osi_common.proto index ec84ed522..74e148c3f 100644 --- a/osi_common.proto +++ b/osi_common.proto @@ -159,7 +159,7 @@ message Dimension3d // \f$ Rotation_{yaw,pitch,roll} = // Rotation_{yaw}*Rotation_{pitch}*Rotation_{roll} \f$ // -// \f$ vector_{gobal coord system} := Rotation_{yaw, pitch, roll} * vector_{local coord system} +local_{origin::position} \f$ +// \f$ vector_{global coord system} := Rotation_{yaw, pitch, roll} * vector_{local coord system} +local_{origin::position} \f$ // // \attention This definition changed in OSI version 3.0.0. Previous OSI // versions (V2.xx) had an other definition. @@ -195,7 +195,7 @@ message Orientation3d // truth, the identifier of an item (object, lane, sign, etc.) must remain // stable over its lifetime. \c Identifier values may be only be reused if the // available address space is exhausted and the specific values have not been in -// use for several timesteps. Sensor specific tracking IDs have no restrictions +// use for several time steps. Sensor specific tracking IDs have no restrictions // and should behave according to the sensor specifications. // // The value MAX(uint64) = 2^(64) -1 = @@ -250,7 +250,7 @@ message ExternalReference // The external identifier reference value. // // The repeated string is chosen as a common description of the external - // identifier, because a variety of identificatier types could be + // identifier, because a variety of identifier types could be // involved . // // For example, referencing a unique lane in OpenDRIVE requires the diff --git a/osi_detectedobject.proto b/osi_detectedobject.proto index 030747f06..fb4e4e62b 100644 --- a/osi_detectedobject.proto +++ b/osi_detectedobject.proto @@ -80,11 +80,11 @@ message DetectedItemHeader // MEASUREMENT_STATE_OTHER = 1; - // Entity has been measured by the sensor in the current timestep. + // Entity has been measured by the sensor in the current time step. // MEASUREMENT_STATE_MEASURED = 2; - // Entity has not been measured by the sensor in the current timestep. + // Entity has not been measured by the sensor in the current time step. // Values provided by tracking only. // MEASUREMENT_STATE_PREDICTED = 3; diff --git a/osi_featuredata.proto b/osi_featuredata.proto index 69b4fcd62..c4079fe21 100644 --- a/osi_featuredata.proto +++ b/osi_featuredata.proto @@ -36,7 +36,7 @@ message FeatureData // // \note Required for ultrasonic sensors: Detections will be send by the // emitting ultrasonic sensor, including all indirect detections received - // by neighbouring sensors. + // by neighboring sensors. // repeated UltrasonicDetectionData ultrasonic_sensor = 4; @@ -332,7 +332,7 @@ message RadarDetection // // \note Unambiguous measurements have the ambiguity ID 0. // - // \note Multiple seperate detections, from e.g. a large object, do not + // \note Multiple separate detections, from e.g. a large object, do not // necessarily on their own create any ambiguity. Therefore they do not // usually share an ambiguity ID. They can however be ambiguous // with other detections. @@ -509,7 +509,7 @@ message UltrasonicDetectionSpecificHeader // // \image html OSI_USSensor.svg // -// \note Direct detecions lies on circles with the sending sensor as centre. +// \note Direct detections lie on circles with the sending sensor as centre. // message UltrasonicDetectionData { @@ -544,7 +544,7 @@ message UltrasonicDetectionData // // \image html OSI_USSensor_direct.svg // -// \note Direct detecions lies on circles with the sensor as centre. +// \note Direct detections lie on circles with the sensor as centre. // message UltrasonicDetection { @@ -594,7 +594,7 @@ message UltrasonicDetection // // \image html OSI_USSensor_indirect.svg // -// \note Indirect detecions lies on ellipses with the sending resp. receiving +// \note Indirect detections lie on ellipses with the sending resp. receiving // sensor in the focal points. // message UltrasonicIndirectDetection @@ -730,7 +730,7 @@ message CameraDetection // optional bool shape_classification_background = 5; - // The defined shape is foregroud. + // The defined shape is foreground. // The probability for this classification is at least // \c #shape_classification_probability. // @@ -856,7 +856,7 @@ message CameraDetection // optional bool shape_classification_pedestrian_rear = 26; - // This probability defines the mininimum probability for each selected + // This probability defines the minimum probability for each selected // shape classification. // // \rules @@ -989,7 +989,7 @@ message CameraDetection // Allowed number of referenced points: 2 or 3 // // Allowed number of referenced points = 2: first and third corner of - // the box. Box is alligned horizontal resp. vertical. + // the box. Box is aligned horizontal resp. vertical. // // Allowed number of referenced points = 3: first, second and third // corner of the box. fourth corner is calculated by first+third-second @@ -1057,7 +1057,7 @@ message CameraPoint // optional double existence_probability = 1; - // Measured point refered by one camera detection given in spherical + // Measured point referred by one camera detection given in spherical // coordinates in the sensor coordinate system. // optional Spherical3d point = 2; diff --git a/osi_hostvehicledata.proto b/osi_hostvehicledata.proto index 9467b72a8..18762a14f 100644 --- a/osi_hostvehicledata.proto +++ b/osi_hostvehicledata.proto @@ -144,7 +144,7 @@ message HostVehicleData // OPERATING_STATE_BOARDING = 4; - // Entertainment, navigation or similiar systems can be used by the driver. + // Entertainment, navigation or similar systems can be used by the driver. // The vehicle can not be driven. // Usually the driver sits in the vehicle before or after a drive. // diff --git a/osi_lane.proto b/osi_lane.proto index 702a088d9..975a108b2 100644 --- a/osi_lane.proto +++ b/osi_lane.proto @@ -58,7 +58,7 @@ message Lane // // For example, to reference a lane defined in an OpenDRIVE map // the items should be set as follows: - // * reference = URI to map, can remain empty if identical with definiton + // * reference = URI to map, can remain empty if identical with definition // in \c GroundTruth::map_reference // * type = "net.asam.opendrive" // * identifier[0] = id of t_road @@ -209,8 +209,8 @@ message Lane // cl: center line // lb: lane boundary // - // \attention The points desribing the center line must be set in the - // same ordering (ascending or descending) as the points desribing the + // \attention The points describing the center line must be set in the + // same ordering (ascending or descending) as the points describing the // lane boundaries. Example: If the points are deducted from a map format, // the order of points is recommended to be in line with the road coordinate // (e.g. s-coordinate in OpenDRIVE). @@ -441,7 +441,7 @@ message Lane // SUBTYPE_NORMAL = 2; - // A lane that is designated for bicylists. + // A lane that is designated for bicycles. // // Since it is not intended to be used for normal automotive // driving, it should be used in combination with TYPE_NONDRIVING. diff --git a/osi_logicallane.proto b/osi_logicallane.proto index 5d3828673..35f58b51d 100644 --- a/osi_logicallane.proto +++ b/osi_logicallane.proto @@ -318,7 +318,7 @@ message LogicalLaneBoundary // - The red area is the area where \c l1 overlaps \c l2. This is recorded in // #overlapping_lane of \c l1. // -// As can be seen in the images, the two highlighted lanes are neighbours for +// As can be seen in the images, the two highlighted lanes are neighbors for // part of their length, but it makes no sense for them to have the same // reference line, since they diverge significantly. // @@ -347,7 +347,7 @@ message LogicalLane // // For example, to reference a lane defined in an OpenDRIVE map // the items should be set as follows: - // * reference = URI to map, can remain empty if identical with definiton + // * reference = URI to map, can remain empty if identical with definition // in \c GroundTruth::map_reference // * type = "net.asam.opendrive" // * identifier[0] = id of t_road @@ -420,10 +420,10 @@ message LogicalLane // not required that the reference line has the same direction as the // driving direction of the lane. // - // Neighbouring lanes (i.e. lanes that are neighbours and whose directions + // Neighboring lanes (i.e. lanes that are neighbors and whose directions // do not diverge significantly) are strongly encouraged to reference the // same ReferenceLine, so that vehicles that are next to each other on - // neighbouring lanes have comparable S positions. + // neighboring lanes have comparable S positions. // // The S coordinate of the reference line makes it easy to find e.g. which // object is next on a lane, using the LogicalLaneAssignment of the @@ -616,7 +616,7 @@ message LogicalLane // TYPE_NORMAL = 2; - // A lane that is designated for bicylists. + // A lane that is designated for bicycles // Note that biking lanes that cross the road (e.g. on an intersection) // are also labeled with this type. // diff --git a/osi_object.proto b/osi_object.proto index fa879188a..3fcc79fe0 100644 --- a/osi_object.proto +++ b/osi_object.proto @@ -252,7 +252,7 @@ message StationaryObject // MATERIAL_STONE = 6; - // Glas structure. + // Glass structure. // MATERIAL_GLAS = 7; @@ -609,7 +609,7 @@ message MovingObject repeated WheelData wheel_data = 7; // Angle of the steering wheel. - // Zero means the steering wheel is in its center postion, a positive value + // Zero means the steering wheel is in its center position, a positive value // means the steering wheel is turned to the left and a negative value // means the steering wheel is turned to the right of the center position. // @@ -752,7 +752,7 @@ message MovingObject // TYPE_MEDIUM_CAR in OSI. // // \note Vehicle type classification is a complex area and there are no - // universally recognised standards. As such, the boundaries between some of the + // universally recognized standards. As such, the boundaries between some of the // OSI vehicle types are not well-defined. It is left to the implementor to // decide how to distinguish between them and agree that with any applications which // make use of that specific interface instance. For example, how to distinguish @@ -782,7 +782,7 @@ message MovingObject // Vehicle is a medium car. // - // Definition: Hatchback or sedan with lenght between 4.5 and 5 m. + // Definition: Hatchback or sedan with length between 4.5 and 5 m. // TYPE_MEDIUM_CAR = 4; diff --git a/osi_referenceline.proto b/osi_referenceline.proto index 72fa312a8..f4c246371 100644 --- a/osi_referenceline.proto +++ b/osi_referenceline.proto @@ -53,7 +53,7 @@ message ReferenceLine // ReferenceLine is a polyline, where the coordinates of points are // calculated by projection onto the nearest point on the line. // - // \attention DEPRECATED: Due to the shortcomings documenten below, this + // \attention DEPRECATED: Due to the shortcomings documented below, this // type will be removed in 4.0.0. // TYPE_POLYLINE = 0; diff --git a/osi_sensorview.proto b/osi_sensorview.proto index 863a5c2bb..26f0d5883 100644 --- a/osi_sensorview.proto +++ b/osi_sensorview.proto @@ -301,7 +301,7 @@ message LidarSensorView // normal to surface angle. // - // The normal of the transmitted beam to the object, roadmarking etc + // The normal of the transmitted beam to the object, road marking etc // encounter. \note data is in Lidar coordinate system // // Unit: unit vector @@ -309,7 +309,7 @@ message LidarSensorView optional Vector3d normal_to_surface = 5; // ID of the detected object this reflection is associated to. - // can be used for raytracing debug + // can be used for ray tracing debug // // \note ID = MAX(uint64) indicates no reference to an object. optional Identifier object_id = 6; diff --git a/osi_streamingupdate.proto b/osi_streamingupdate.proto index f3006fee9..ceafb05cd 100644 --- a/osi_streamingupdate.proto +++ b/osi_streamingupdate.proto @@ -23,7 +23,7 @@ package osi3; // // \note The receiver of partial streaming update messages can only rely on the // most up-to-date information at the corresponding timestamp. E.g. omitting -// objects does not indicate static behaviour but it may be sufficient for the +// objects does not indicate static behavior but it may be sufficient for the // use case to update certain objects at a later point in time. // message StreamingUpdate diff --git a/osi_trafficcommand.proto b/osi_trafficcommand.proto index 5baef7731..d2861475a 100644 --- a/osi_trafficcommand.proto +++ b/osi_trafficcommand.proto @@ -67,7 +67,7 @@ message TrafficCommand // // \note This message is notionally a multiple choice selection, that is, only // certain combinations of atomic traffic actions shall be transmitted within -// certain time intervals, for example, for plausibity reasons. The restrictions +// certain time intervals, for example, for plausibility reasons. The restrictions // regarding that are not part of this message, yet are seen as a task of the // scenario description, for example, OpenSCENARIO. // @@ -197,19 +197,19 @@ message TrafficAction // message DynamicConstraints { - // Maximum acceleration the distance contoller is allowed to use for keeping distance. + // Maximum acceleration the distance controller is allowed to use for keeping distance. // // Unit: m/s^2 // optional double max_acceleration = 1; - // Maximum deceleration the distance contoller is allowed to use for keeping distance. + // Maximum deceleration the distance controller is allowed to use for keeping distance. // // Unit: m/s^2 // optional double max_deceleration = 2; - // Maximum speed the distance contoller is allowed to use for keeping distance. + // Maximum speed the distance controller is allowed to use for keeping distance. // // Unit: m/s // @@ -465,7 +465,7 @@ message TrafficAction // \brief End actions action. // - // This action tells a traffic participant that the exection of the + // This action tells a traffic participant that the execution of the // referenced actions is regarded as successfully performed. The // termination of the referenced actions is allowed to be performed // gracefully. @@ -552,11 +552,11 @@ message TrafficAction // participant receiving this action and the reference traffic // participant. // True: Longitudinal distance is measured using the distance between closest bounding box points. - // False: Longitudinal distance is mesasured using the distance between the center of each object's bounding box. + // False: Longitudinal distance is measured using the distance between the center of each object's bounding box. // optional bool freespace = 4; - // Define wheather the traffic participant should only reach the distance once + // Define whether the traffic participant should only reach the distance once // or if it should also keep the distance after having reached it. // True: the traffic participant shall approach the reference participant // and follow with the distance specified until the action is aborted (communicate with AbortActionsAction). @@ -565,7 +565,7 @@ message TrafficAction // optional bool follow = 5; - // Parameter that assings either unlimited dynamics (if omitted) + // Parameter that assigns either unlimited dynamics (if omitted) // or limited maxAcceleration/maxDeceleration/maxSpeed to the action. // optional DynamicConstraints dynamic_constraints = 6; @@ -605,11 +605,11 @@ message TrafficAction // participant receiving this action and the reference traffic // participant. // True: Lateral distance is measured using the distance between closest bounding box points. - // False: Lateral distance is mesasured using the distance between the center of each object's bounding box. + // False: Lateral distance is measured using the distance between the center of each object's bounding box. // optional bool freespace = 4; - // Define wheather the traffic participant should only reach the distance once + // Define whether the traffic participant should only reach the distance once // or if it should also keep the distance after having reached it. // True: the traffic participant shall approach the reference participant // and follow with the distance specified until the action is aborted (communicate with AbortActionsAction). @@ -618,7 +618,7 @@ message TrafficAction // optional bool follow = 5; - // Parameter that assings either unlimited dynamics (if omitted) + // Parameter that assigns either unlimited dynamics (if omitted) // or limited maxAcceleration/maxDeceleration/maxSpeed to the action. // optional DynamicConstraints dynamic_constraints = 6; diff --git a/osi_trafficlight.proto b/osi_trafficlight.proto index fe90fd4b4..6dfba2929 100644 --- a/osi_trafficlight.proto +++ b/osi_trafficlight.proto @@ -124,7 +124,7 @@ message TrafficLight // Boolean flag to indicate that the traffic light is taken out of service. // This can be achieved by visibly crossing the light, covering it completely - // or swiching the traffic light off. + // or switching the traffic light off. // optional bool is_out_of_service = 6; diff --git a/osi_trafficupdate.proto b/osi_trafficupdate.proto index 45a87d6fb..277766121 100644 --- a/osi_trafficupdate.proto +++ b/osi_trafficupdate.proto @@ -20,7 +20,7 @@ package osi3; // information is provided as a MovingObject. Certain fields of this // sub-message are not required to be set and will be ignored by the // simulation environment, because they are static information. -// Instead of creating a seperate message type for only the non-static +// Instead of creating a separate message type for only the non-static // information, re-use existing message. // message TrafficUpdate From 54064e103bbe1a7acdd58a097ce4a3a060992f15 Mon Sep 17 00:00:00 2001 From: ClemensLinnhoff Date: Wed, 14 Feb 2024 16:30:09 +0100 Subject: [PATCH 026/113] Add spellchecking action Signed-off-by: ClemensLinnhoff --- .github/.pyspelling.yml | 19 +++ .github/spelling_custom_words_en_US.txt | 203 ++++++++++++++++++++++++ .github/workflows/protobuf.yml | 10 ++ 3 files changed, 232 insertions(+) create mode 100644 .github/.pyspelling.yml create mode 100644 .github/spelling_custom_words_en_US.txt diff --git a/.github/.pyspelling.yml b/.github/.pyspelling.yml new file mode 100644 index 000000000..5670d5b6e --- /dev/null +++ b/.github/.pyspelling.yml @@ -0,0 +1,19 @@ +matrix: +- name: Proto + aspell: + lang: en + d: en_US + camel-case: true + sources: + - ./*.proto + dictionary: + wordlists: + - .github/spelling_custom_words_en_US.txt + output: build/dictionary/proto.dic + pipeline: + - pyspelling.filters.context: + context_visible_first: false + escapes: '\\[\\`~]' + delimiters: + - open: '(?s)^(?P *\/\/)' + close: '^(?P=open)$' diff --git a/.github/spelling_custom_words_en_US.txt b/.github/spelling_custom_words_en_US.txt new file mode 100644 index 000000000..103df1e0d --- /dev/null +++ b/.github/spelling_custom_words_en_US.txt @@ -0,0 +1,203 @@ +adas +agbl +al +Anglais +arg +asam +atsc +bbcenter +Beauce +Begriffe +Beleuchtung +Bereich +bgbl +bggr +Biblio +bool +boolean +Botts +br +britannica +candela +cartesian +cd +centerline +Cianciaruso +CIE +cie +clothoid +cmyk +coord +courtneystrong +Crabb +css +customizable +dBm +de +delineator +der +detections +Deutsches +discretized +dms +doi +doppler +drivable +dt +easting +edn +edu +egm +eilvterm +Einheiten +Elsevier +endcode +endlink +endrules +engl +enum +enums +eoas +epochconverter +et +euler +executability +Fahrverhalten +Fahrzeugdynamik +fcm +fmu +Formelsammlung +Formelzeichen +fov +fp +Frei +fuer +fullreports +Gedeon +Geospatial +github +GNSS +gridded +Groessen +GroundTruthInit +Hagen +href +hsv +htm +html +http +https +hypot +ietf +illuminance +ilv +im +incrementing +Institut +Intl +io +iso +itu +jpg +kfz +Lambertian +Laperriere +latencies +Lichttechnik +lidar +lidar's +lm +lte +luminance +luv +lx +Meteorologische +metoffice +milliwatt +nd +Nicolaus +noao +Normung +northing +ns +num +oktas +onlinepubs +opengroup +optischen +Ordnung +osi +osmp +parametrization +Paulat +pdf +png +polyline +POSIX +powertrain +pre +priori +proj +proto +protobuf +pubrec +px +QLTkit +rbd +rcs +README +rfc +rgb +rgbir +rggb +rmse +Rosenberger +SAE +sae +Schlupf +SEMITRACTOR +signalway +sl +snr +sr +sslnet +steradian +Strahlungsphysik +Strassenfahrzeuge +Strassenverkehrs +strassenverkehrsordnung +StVO +StVZO +subtype +svg +Tait +tf +tf +th +Thibodeau +todo +trilateration +tupel +ubc +ubc +uint +uk +und +unix +uri +vda +vzkat +wa +Wernli +wgs +wikipedia +wp +wsdot +www +www +xrat +xy +xyz +xz +Zeitschrift +Zou \ No newline at end of file diff --git a/.github/workflows/protobuf.yml b/.github/workflows/protobuf.yml index da70a5db3..8bd4c37cc 100644 --- a/.github/workflows/protobuf.yml +++ b/.github/workflows/protobuf.yml @@ -11,6 +11,16 @@ on: branches: [ master ] jobs: + spellcheck: + name: Spellcheck + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v3 + - uses: rojopolis/spellcheck-github-actions@0.36.0 + name: Spellcheck + with: + config_path: .github/.pyspelling.yml + build-proto2-linux64: name: Build Proto2 Linux 64 From 2c30254c2446f5c1e1ea68710d0234965fab6168 Mon Sep 17 00:00:00 2001 From: ClemensLinnhoff Date: Wed, 14 Feb 2024 16:58:30 +0100 Subject: [PATCH 027/113] Add German words for traffic signs Signed-off-by: ClemensLinnhoff --- .github/spelling_custom_words_en_US.txt | 178 +++++++++++++++++++++++- 1 file changed, 177 insertions(+), 1 deletion(-) diff --git a/.github/spelling_custom_words_en_US.txt b/.github/spelling_custom_words_en_US.txt index 103df1e0d..97baf1426 100644 --- a/.github/spelling_custom_words_en_US.txt +++ b/.github/spelling_custom_words_en_US.txt @@ -1,41 +1,80 @@ +abc +absteigen adas +ADR agbl al +Allgemeine +Altenheim +Anfang Anglais +anlage +Anlieger arg asam atsc +au +auch +auf +auml +Ausfahrt +Baugebiet +Baustelle +Baustellen +Baustellenausfahrt bbcenter Beauce +befahrbar +befahren Begriffe +bei Beleuchtung +Benrath Bereich +berholt +Besondere +Bewohner bgbl bggr Biblio +bicyclesback +bildgebendes bool boolean Botts +bp br britannica candela cartesian +Cattles +cattles cd +cellpadding +cellspacing centerline +chen Cianciaruso CIE cie clothoid cmyk +CNG +colspan +CONNECTINGRAMP +contraints coord courtneystrong Crabb css customizable +daytimes dBm de delineator +dem der +des detections Deutsches discretized @@ -44,44 +83,81 @@ doi doppler drivable dt +Duesseldorf +Durchgangsverkehr +dvr easting +EBIKES edn edu egm eilvterm +ein Einheiten +Elektrotechnik +ellpadding Elsevier endcode +Ende +Endeninch endlink endrules engl +enschaden enum enums eoas epochconverter +erlaubt et euler +EV executability +Fachthemen +Fahrbahn +Fahrbahnbelag +Fahrbahnmarkierung Fahrverhalten Fahrzeugdynamik +Fak fcm +fehlende +Feiertagen fmu Formelsammlung Formelzeichen fov fp Frei +frei fuer fullreports +ge +geb Gedeon +Gefahrenzeichen +gekennzeichneten +gekennzeichneter +Gelegenheitsverkehr Geospatial +gesetze github +glichkeit GNSS gridded Groessen GroundTruthInit +gulleys +haben +Hafengebiet Hagen +halten +hier +Hochwasser href +hrend +hrenpflichtig +hrung hsv htm html @@ -92,76 +168,142 @@ ietf illuminance ilv im +Immission incrementing +Industriegebiet +innerhalb Institut Intl io +IRI iso itu jpg +Karamihas +Karlsruhe +keine kfz +Krankenhaus +Kreis +kreuzt +Kuppe +Ladevorgangs +Ladezone Lambertian Laperriere latencies Lichttechnik lidar lidar's +Linksabbieger lm +lspur lte luminance luv lx +Mainz Meteorologische metoffice milliwatt +mit +Modellierung +MULTITRACK nd +nde +ndert +ne +NEBEL +Nebenstrecke +neuer +nicht Nicolaus noao +NONDRIVING Normung northing +Nr ns num +Nur +nur +oder +OFFRAMP oktas +ONEWAY onlinepubs +ONRAMP opengroup optischen Ordnung osi osmp +Ouml +ouml parametrization +Parkausweis +Parken +Parkfl +Parkschein +Parkst Paulat pdf png +Polizeikontrolle polyline +positionally POSIX powertrain pre +preannouncement priori proj proto protobuf +publikationen pubrec px QLTkit +Rauch rbd rcs +rdquo README +Rei rfc +rfen rgb rgbir rggb +Richtzeichen +rmschutz rmse +Rollsplitt Rosenberger +Sa SAE sae +samstags +Schienenfahrzeuge +Schleudergefahr Schlupf +Schulbus +Schule +Schulweg +Seitenstreifen SEMITRACTOR signalway sl snr +Sonn +specular +Sprengarbeiten +Spurrinnen sr sslnet +Steinburg steradian +Stra Strahlungsphysik Strassenfahrzeuge Strassenverkehrs @@ -169,35 +311,69 @@ strassenverkehrsordnung StVO StVZO subtype +subtypes svg +szlig Tait +td tf tf th Thibodeau +tml todo trilateration +tt tupel ubc ubc uint uk +umen +umich +umtri und +Unfall +UNGATED +Universitaet unix uri +uuml vda +verkehr +Verkehrseinrichtungen +Verkehrsf +Verkehrstechnik +verkehrszeichen +verschluss +Verschmutzte +Vorfahrt +Vorschriftzeichen +Vorweg +vz vzkat +VzKat wa +Welle +Wellenausbreitung +Wendem +werden +werktags Wernli wgs +Wiesbaden wikipedia +Wilster wp wsdot www www xrat +XXXX xy xyz xz Zeitschrift -Zou \ No newline at end of file +Zou +Zufahrt +Zuflussregelung From c2f15096bb5ce3476f661af7530ccdfc9662acea Mon Sep 17 00:00:00 2001 From: ClemensLinnhoff Date: Wed, 14 Feb 2024 17:23:33 +0100 Subject: [PATCH 028/113] More spelling fixes Signed-off-by: ClemensLinnhoff --- .github/spelling_custom_words_en_US.txt | 14 ++++++++++++-- osi_common.proto | 2 +- osi_environment.proto | 6 +++--- osi_featuredata.proto | 8 ++++---- osi_hostvehicledata.proto | 2 +- osi_lane.proto | 2 +- osi_logicaldetectiondata.proto | 2 +- osi_logicallane.proto | 2 +- osi_object.proto | 10 +++++----- osi_referenceline.proto | 10 +++++----- osi_roadmarking.proto | 2 +- osi_sensorviewconfiguration.proto | 2 +- osi_trafficcommand.proto | 6 +++--- osi_trafficsign.proto | 22 +++++++++++----------- 14 files changed, 50 insertions(+), 40 deletions(-) diff --git a/.github/spelling_custom_words_en_US.txt b/.github/spelling_custom_words_en_US.txt index 97baf1426..7f7f5fa70 100644 --- a/.github/spelling_custom_words_en_US.txt +++ b/.github/spelling_custom_words_en_US.txt @@ -28,13 +28,13 @@ befahrbar befahren Begriffe bei -Beleuchtung +beleuchtung Benrath Bereich berholt Besondere Bewohner -bgbl +BGBl bggr Biblio bicyclesback @@ -68,6 +68,7 @@ courtneystrong Crabb css customizable +dataset daytimes dBm de @@ -97,6 +98,7 @@ Einheiten Elektrotechnik ellpadding Elsevier +Encyclopaedia endcode Ende Endeninch @@ -173,6 +175,7 @@ incrementing Industriegebiet innerhalb Institut +interoperable Intl io IRI @@ -234,6 +237,8 @@ ONEWAY onlinepubs ONRAMP opengroup +opendrive +openscenario optischen Ordnung osi @@ -241,6 +246,7 @@ osmp Ouml ouml parametrization +parametrize Parkausweis Parken Parkfl @@ -264,6 +270,7 @@ publikationen pubrec px QLTkit +radiocommunication Rauch rbd rcs @@ -309,12 +316,15 @@ Strassenfahrzeuge Strassenverkehrs strassenverkehrsordnung StVO +stvo StVZO subtype subtypes +superelevation svg szlig Tait +TBD td tf tf diff --git a/osi_common.proto b/osi_common.proto index 74e148c3f..b0e0bcd6c 100644 --- a/osi_common.proto +++ b/osi_common.proto @@ -204,7 +204,7 @@ message Orientation3d // message Identifier { - // The identifier's value. + // The value of the identifier. // // \rules // is_greater_than_or_equal_to: 0 diff --git a/osi_environment.proto b/osi_environment.proto index fb77438fc..43db20453 100644 --- a/osi_environment.proto +++ b/osi_environment.proto @@ -40,7 +40,7 @@ message EnvironmentalConditions // sorted by languages](https://www.epochconverter.com/#code). // // \par References: - // [1] ITU Radiocommunication Assembly. (2002). Recommondation ITU-R TF.460-6 Standard-frequency and time-signal emissions. (Rec. ITU-R TF.460-6). Retrieved January 25, 2020, from http://www.itu.int/dms_pubrec/itu-r/rec/tf/R-REC-TF.460-6-200202-I!!PDF-E.pdf \n + // [1] ITU Radiocommunication Assembly. (2002). Recommendation ITU-R TF.460-6 Standard-frequency and time-signal emissions. (Rec. ITU-R TF.460-6). Retrieved January 25, 2020, from http://www.itu.int/dms_pubrec/itu-r/rec/tf/R-REC-TF.460-6-200202-I!!PDF-E.pdf \n // [2] The Open Group. (2018). POSIX.1-2017 The Open Group Base Specifications Issue 7, 2018 edition. IEEE Std 1003.1-2017 (Revision of IEEE Std 1003.1-2008). Retrieved January 25, 2020, from https://pubs.opengroup.org/onlinepubs/9699919799/xrat/contents.html // optional int64 unix_timestamp = 8; @@ -176,7 +176,7 @@ message EnvironmentalConditions // \par References: // [1] Shepard, F. D. (1996). Reduced visibility due to fog on the highway. Transportation Research Board, National Research Council (Ed.). National Academy Press. Washington, D.C., USA. ISBN 0-309-06006-0. \n // [2] Strassenverkehrs-Ordnung (StVO) as of dated March 06, 2013 (BGBl. I S. 367), lastly changed by article 4a of the order from June 06, 2019 (BGBl. I S. 756). \n - // [3] stvo.de. (2013, April 01). StVO Par. 17 Beleuchtung. Retrieved January 25, 2020, from https://www.stvo.de/strassenverkehrsordnung/101-17-beleuchtung \n + // [3] StVO.de. (2013, April 01). StVO Par. 17 Beleuchtung. Retrieved January 25, 2020, from https://www.StVO.de/strassenverkehrsordnung/101-17-beleuchtung \n // [4] Meteorological Office UK. (2020). Homepage of the Meteorological Office - How we measure visibility. Retrieved January 25, 2020, from http://www.metoffice.gov.uk/guide/weather/observations-guide/how-we-measure-visibility // enum Fog @@ -358,7 +358,7 @@ message EnvironmentalConditions // 8 oktas means that the sky is completely covered with clouds and no sky blue can be recognized. // // \par References: - // [1] CIE engl. International Commission on Illumination. (2020). CIE S017:2020 ILV: Intl. Lighitng Vocabulary, 2nd edn.. Retrieved March 8, 2022, from https://cie.co.at/eilvterm/17-29-116 \n + // [1] CIE engl. International Commission on Illumination. (2020). CIE S017:2020 ILV: Intl. Lighting Vocabulary, 2nd edn.. Retrieved March 8, 2022, from https://cie.co.at/eilvterm/17-29-116 \n // [2] UBC The University of British Columbia. (2018). ATSC 113 Weather for Sailing, Flying & Snow Sports. Retrieved March 8, 2022, from https://www.eoas.ubc.ca/courses/atsc113/flying/met_concepts/01-met_concepts/01c-cloud_coverage/index.html // enum FractionalCloudCover diff --git a/osi_featuredata.proto b/osi_featuredata.proto index c4079fe21..5856e1f87 100644 --- a/osi_featuredata.proto +++ b/osi_featuredata.proto @@ -222,7 +222,7 @@ message SensorDetectionHeader // EXTENDED_QUALIFIER_INPUT_NOT_AVAILABLE = 9; - // Internal reason (e.g. an internal HW or SW error has occurred). + // Internal reason (e.g. an internal hardware or software error has occurred). // EXTENDED_QUALIFIER_INTERNAL_REASON = 10; @@ -459,7 +459,7 @@ message LidarDetection // \endrules // // \par Reference: - // [1] Rosenberger, P., Holder, M.F., Cianciaruso, N. et al. (2020). Sequential lidar sensor system simulation: a modular approach for simulation-based safety validation of automated driving Automot. Engine Technol. 5, Fig 7, Fig 8. Retrieved May 10, 2021, from https://doi.org/10.1007/s41104-020-00066-x + // [1] Rosenberger, P., Holder, M.F., Cianciaruso, N. et al. (2020). Sequential lidar sensor system simulation: a modular approach for simulation-based safety validation of automated driving Automotive Engine Technology 5, Fig 7, Fig 8. Retrieved May 10, 2021, from https://doi.org/10.1007/s41104-020-00066-x // optional double echo_pulse_width = 11; @@ -509,7 +509,7 @@ message UltrasonicDetectionSpecificHeader // // \image html OSI_USSensor.svg // -// \note Direct detections lie on circles with the sending sensor as centre. +// \note Direct detections lie on circles with the sending sensor as center. // message UltrasonicDetectionData { @@ -544,7 +544,7 @@ message UltrasonicDetectionData // // \image html OSI_USSensor_direct.svg // -// \note Direct detections lie on circles with the sensor as centre. +// \note Direct detections lie on circles with the sensor as center. // message UltrasonicDetection { diff --git a/osi_hostvehicledata.proto b/osi_hostvehicledata.proto index 18762a14f..9594e8e68 100644 --- a/osi_hostvehicledata.proto +++ b/osi_hostvehicledata.proto @@ -568,7 +568,7 @@ message HostVehicleData // STATE_OTHER = 1; - // The function has errored in some way that renders it ineffective. + // The function has thrown an error in some way that renders it ineffective. // STATE_ERRORED = 2; diff --git a/osi_lane.proto b/osi_lane.proto index 975a108b2..2ac6b0094 100644 --- a/osi_lane.proto +++ b/osi_lane.proto @@ -189,7 +189,7 @@ message Lane // Indicates that the host vehicle travels on this particular lane. // The host vehicle may travel on more than one lane at once. This does - // also apply for the \c CanditateLane in the \c DetectedLane . + // also apply for the \c CandidateLane in the \c DetectedLane . // optional bool is_host_vehicle_lane = 2; diff --git a/osi_logicaldetectiondata.proto b/osi_logicaldetectiondata.proto index 353abd407..fb7d09f11 100644 --- a/osi_logicaldetectiondata.proto +++ b/osi_logicaldetectiondata.proto @@ -223,7 +223,7 @@ message LogicalDetection // \endrules // // \par Reference: - // [1] Rosenberger, P., Holder, M.F., Cianciaruso, N. et al. (2020). Sequential lidar sensor system simulation: a modular approach for simulation-based safety validation of automated driving Automot. Engine Technol. 5, Fig 7, Fig 8. Retrieved May 10, 2021, from https://doi.org/10.1007/s41104-020-00066-x + // [1] Rosenberger, P., Holder, M.F., Cianciaruso, N. et al. (2020). Sequential lidar sensor system simulation: a modular approach for simulation-based safety validation of automated driving Automotive Engine Technology 5, Fig 7, Fig 8. Retrieved May 10, 2021, from https://doi.org/10.1007/s41104-020-00066-x // optional double echo_pulse_width = 12; } diff --git a/osi_logicallane.proto b/osi_logicallane.proto index 35f58b51d..e55437011 100644 --- a/osi_logicallane.proto +++ b/osi_logicallane.proto @@ -590,7 +590,7 @@ message LogicalLane // // Definition of available lane types. // - // This is mostly aligned with OpenDRIVE, except that lane types modelling + // This is mostly aligned with OpenDRIVE, except that lane types modeling // access restrictions (e.g. "taxi") are not made available here. These are // already deprecated in OpenDRIVE. To support this, access restrictions // should be added later, in alignment with OpenDRIVE. diff --git a/osi_object.proto b/osi_object.proto index 3fcc79fe0..cf59d6bc7 100644 --- a/osi_object.proto +++ b/osi_object.proto @@ -48,7 +48,7 @@ message StationaryObject // // For example, to reference an object defined in an OpenDRIVE map // the items should be set as follows: - // * reference = URI to map, can remain empty if identical with definiton + // * reference = URI to map, can remain empty if identical with definition // in \c GroundTruth::map_reference // * type = "net.asam.opendrive" // * identifier[0] = "object" for t_road_objects_object and @@ -690,7 +690,7 @@ message MovingObject // optional string model_reference = 9; - // The value describes the kinetic friction of the tyre's contact point. + // The value describes the kinetic friction of the tire's contact point. // If different friction coefficients due to more than one contact points are available, // this value contains the average. // @@ -746,14 +746,14 @@ message MovingObject // other OpenX standards (in particular, OpenScenario 1.x and 2.x, and OpenLabel). // This is primarily for historical reasons. Where a single type from a // different standard can map to multiple OSI types it is left up to the - // discretion of the OSI implementor how that mapping is achieved. For example, + // discretion of the OSI implementer how that mapping is achieved. For example, // a simulator may use the dimensions of a provided 3d model of a vehicle with type // "car" in OpenScenario, to determine whether it should be a TYPE_SMALL_CAR or // TYPE_MEDIUM_CAR in OSI. // // \note Vehicle type classification is a complex area and there are no // universally recognized standards. As such, the boundaries between some of the - // OSI vehicle types are not well-defined. It is left to the implementor to + // OSI vehicle types are not well-defined. It is left to the implementer to // decide how to distinguish between them and agree that with any applications which // make use of that specific interface instance. For example, how to distinguish // between a HEAVY_TRUCK and a DELIVERY_VAN, or a TRAILER and a SEMITRAILER. @@ -853,7 +853,7 @@ message MovingObject // TYPE_WHEELCHAIR = 15; - // Vehicle is a stand-up or kickboard scooter, including + // Vehicle is a stand-up scooter, including // motorized versions. // TYPE_STANDUP_SCOOTER = 17; diff --git a/osi_referenceline.proto b/osi_referenceline.proto index f4c246371..e49faac7d 100644 --- a/osi_referenceline.proto +++ b/osi_referenceline.proto @@ -158,12 +158,12 @@ message ReferenceLine // point on the polyline. The resulting ST coordinate uniquely maps back // to \c P1. // - \c P2 has multiple points "nearest points" on the polyline. - // As can be seen here, two ST coordinates map to \c P2 (red and grey + // As can be seen here, two ST coordinates map to \c P2 (red and gray // dotted line). Following the rules above, the one with the smallest S // value is chosen (the red dotted line). // - \c P3 has a unique "nearest point" on the polyline. However, multiple // points map to the same ST coordinate as that of \c P3, e.g. \c P4 - // (drawn in grey). + // (drawn in gray). // - Finally, \c P5 shows how the reference line is extended infinitely for // points that are "outside" the reference line. // @@ -269,10 +269,10 @@ message ReferenceLine // in OSI. There are a few difficulties with this: // - The T coordinate is nearly the same as for OpenDRIVE, but // unfortunately not perfectly. In OpenDRIVE, if the road is tilted using - // superElevation, then the t coordinate system is tilted along, so the T + // superelevation, then the t coordinate system is tilted along, so the T // coordinate is no longer calculated in the XY plane (as proposed for - // OSI). It doesn't seem feasable to implement the same tilting for OSI, - // so simulation tools will have to consider superElevation and convert + // OSI). It doesn't seem feasible to implement the same tilting for OSI, + // so simulation tools will have to consider superelevation and convert // the T coordinate accordingly: t_OSI = t_OpenDRIVE * // cos(alpha), where alpha is the superelevation angle. // - The angle will not be perfectly the same, due to the use of line diff --git a/osi_roadmarking.proto b/osi_roadmarking.proto index f002f9bb5..ea1b85912 100644 --- a/osi_roadmarking.proto +++ b/osi_roadmarking.proto @@ -67,7 +67,7 @@ message RoadMarking // // For example, to reference a signal defined in an OpenDRIVE map // the items should be set as follows: - // * reference = URI to map, can remain empty if identical with definiton + // * reference = URI to map, can remain empty if identical with definition // in \c GroundTruth::map_reference // * type = "net.asam.opendrive" // * identifier[0] = id of t_road_signals_signal diff --git a/osi_sensorviewconfiguration.proto b/osi_sensorviewconfiguration.proto index 1419c9312..4601d1bc6 100644 --- a/osi_sensorviewconfiguration.proto +++ b/osi_sensorviewconfiguration.proto @@ -184,7 +184,7 @@ message SensorViewConfiguration // update to the sensor input should happen at 0.048s, or 0.018s // after simulation start. This convention is needed to ensure // stable phase position of the offset in the case of changing - // simulation start times, e.g. for partial resimulation. + // simulation start times, e.g. for partial re-simulation. // // Unit: s optional Timestamp update_cycle_offset = 9; diff --git a/osi_trafficcommand.proto b/osi_trafficcommand.proto index d2861475a..61c62a9b6 100644 --- a/osi_trafficcommand.proto +++ b/osi_trafficcommand.proto @@ -77,7 +77,7 @@ message TrafficCommand // model that certain actions must or shall be terminated, there are // explicit actions nested inside this message (AbortActionsAction, // EndActionsAction), which hold a reference to the respective actions. -// Futhermore, there exists a \c TrafficCommandUpdate message for the +// Furthermore, there exists a \c TrafficCommandUpdate message for the // traffic participant to report back on potentially dismissed actions. // message TrafficAction @@ -524,7 +524,7 @@ message TrafficAction // relative to a target traffic participant. The longitudinal distance is defined as the distance // along the centerline of the lane, on which the (host) traffic participant is currently located. // The interpolation strategy between centerline points for calculating - // that distance along the centerline is open to the traffic participant modeller. + // that distance along the centerline is open to the traffic participant modeler. // // \note This action is aligned with LongitudinalDistanceAction of OpenSCENARIO 1.0 // defining the reference traffic participant and the distance. @@ -577,7 +577,7 @@ message TrafficAction // a target traffic participant. The lateral distance is defined along an imaginative perpendicular line // with respect to the centerline of the current (host) traffic participant's lane. // The interpolation strategy between centerline points for calculating that distance along the imaginative - // perpendicular line is open to the traffic participant modeller. + // perpendicular line is open to the traffic participant modeler. // // \note This action is aligned with LateralDistanceAction of OpenSCENARIO 1.0 // defining the reference traffic participant and the distance. diff --git a/osi_trafficsign.proto b/osi_trafficsign.proto index 11e600d4d..fa3a0e4d3 100644 --- a/osi_trafficsign.proto +++ b/osi_trafficsign.proto @@ -3447,7 +3447,7 @@ message TrafficSign // --> // // - // StVO 353 - Valid only until october 2022. + // StVO 353 - Valid only until October 2022. // // // @@ -3817,7 +3817,7 @@ message TrafficSign // --> // // - // StVO 380 - Valid only until october 2022. + // StVO 380 - Valid only until October 2022. // // // @@ -3836,7 +3836,7 @@ message TrafficSign // --> // // - // StVO 381 - Valid only until october 2022 + // StVO 381 - Valid only until October 2022 // // // @@ -3923,7 +3923,7 @@ message TrafficSign // --> // // - // StVO 388 - Valid only until october 2022 + // StVO 388 - Valid only until October 2022 // // // @@ -3940,7 +3940,7 @@ message TrafficSign // --> // // - // StVO 389 - Valid only until october 2022 + // StVO 389 - Valid only until October 2022 // // // @@ -5374,7 +5374,7 @@ message TrafficSign // // // - // \note Additional traffic signs are modelled as separate main + // \note Additional traffic signs are modeled as separate main // signs. // TYPE_MOBILE_LANE_CLOSURE = 139; @@ -6761,7 +6761,7 @@ message TrafficSign // [\c rules above](\ref TYPE_TIME). //
// See also: [\c Two time ranges](\ref StVO_1040-31), - // [\c Working days except saturdays](\ref StVO_1042-38). + // [\c Working days except Saturdays](\ref StVO_1042-38). // // // @@ -6790,7 +6790,7 @@ message TrafficSign // ”werktags außer samstags” // // - // Working days except saturdays. + // Working days except Saturdays. // // // @@ -8198,7 +8198,7 @@ message TrafficSign // \c #ACTOR_BUSES // // - // Except buses in ocasional service. + // Except buses in occasional service. //
// Set \c TrafficSignValue::text as "im Gelegenheitsverkehr". // @@ -9454,7 +9454,7 @@ message TrafficSign // DIRECTION_DIRECT_135_DEG_LEFT = 9; - // A straight arrow pointing oposite to the direction of + // A straight arrow pointing opposite to the direction of // driving. // DIRECTION_DIRECT_180_DEG = 10; @@ -9540,7 +9540,7 @@ message TrafficSign DIRECTION_CIRCLE_135_DEG_LEFT = 25; // An arrow that includes a fraction of a circle and points - // in the oposite to the direction of driving. Can be used + // in the opposite to the direction of driving. Can be used // in detours in roundabouts. // DIRECTION_CIRCLE_180_DEG = 26; From 619c82070fbf3b0ce841de7995b3855f98996b03 Mon Sep 17 00:00:00 2001 From: ClemensLinnhoff Date: Wed, 14 Feb 2024 17:45:52 +0100 Subject: [PATCH 029/113] Revert svto correction in url Signed-off-by: ClemensLinnhoff --- osi_environment.proto | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osi_environment.proto b/osi_environment.proto index 43db20453..d5c252ebc 100644 --- a/osi_environment.proto +++ b/osi_environment.proto @@ -176,7 +176,7 @@ message EnvironmentalConditions // \par References: // [1] Shepard, F. D. (1996). Reduced visibility due to fog on the highway. Transportation Research Board, National Research Council (Ed.). National Academy Press. Washington, D.C., USA. ISBN 0-309-06006-0. \n // [2] Strassenverkehrs-Ordnung (StVO) as of dated March 06, 2013 (BGBl. I S. 367), lastly changed by article 4a of the order from June 06, 2019 (BGBl. I S. 756). \n - // [3] StVO.de. (2013, April 01). StVO Par. 17 Beleuchtung. Retrieved January 25, 2020, from https://www.StVO.de/strassenverkehrsordnung/101-17-beleuchtung \n + // [3] StVO.de. (2013, April 01). StVO Par. 17 Beleuchtung. Retrieved January 25, 2020, from https://www.stvo.de/strassenverkehrsordnung/101-17-beleuchtung \n // [4] Meteorological Office UK. (2020). Homepage of the Meteorological Office - How we measure visibility. Retrieved January 25, 2020, from http://www.metoffice.gov.uk/guide/weather/observations-guide/how-we-measure-visibility // enum Fog From 0236f6568f2c8447db4f00aa3d117c5023cbfa85 Mon Sep 17 00:00:00 2001 From: Clemens Linnhoff Date: Mon, 26 Feb 2024 10:12:59 +0100 Subject: [PATCH 030/113] Update osi_sensorview.proto Co-authored-by: Pierre R. Mai Signed-off-by: Clemens Linnhoff --- osi_sensorview.proto | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osi_sensorview.proto b/osi_sensorview.proto index 26f0d5883..84e4cf4c3 100644 --- a/osi_sensorview.proto +++ b/osi_sensorview.proto @@ -301,7 +301,7 @@ message LidarSensorView // normal to surface angle. // - // The normal of the transmitted beam to the object, road marking etc + // The normal of the transmitted beam to the object, road marking, etc. // encounter. \note data is in Lidar coordinate system // // Unit: unit vector From 9171f90b16b856fe43b6ea902be8b94b43fce7d6 Mon Sep 17 00:00:00 2001 From: Clemens Linnhoff Date: Mon, 26 Feb 2024 10:13:27 +0100 Subject: [PATCH 031/113] Update osi_environment.proto Co-authored-by: Pierre R. Mai Signed-off-by: Clemens Linnhoff --- osi_environment.proto | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osi_environment.proto b/osi_environment.proto index d5c252ebc..ae3c55011 100644 --- a/osi_environment.proto +++ b/osi_environment.proto @@ -176,7 +176,7 @@ message EnvironmentalConditions // \par References: // [1] Shepard, F. D. (1996). Reduced visibility due to fog on the highway. Transportation Research Board, National Research Council (Ed.). National Academy Press. Washington, D.C., USA. ISBN 0-309-06006-0. \n // [2] Strassenverkehrs-Ordnung (StVO) as of dated March 06, 2013 (BGBl. I S. 367), lastly changed by article 4a of the order from June 06, 2019 (BGBl. I S. 756). \n - // [3] StVO.de. (2013, April 01). StVO Par. 17 Beleuchtung. Retrieved January 25, 2020, from https://www.stvo.de/strassenverkehrsordnung/101-17-beleuchtung \n + // [3] stvo.de. (2013, April 01). StVO Par. 17 Beleuchtung. Retrieved January 25, 2020, from https://www.stvo.de/strassenverkehrsordnung/101-17-beleuchtung \n // [4] Meteorological Office UK. (2020). Homepage of the Meteorological Office - How we measure visibility. Retrieved January 25, 2020, from http://www.metoffice.gov.uk/guide/weather/observations-guide/how-we-measure-visibility // enum Fog From 0cf00c05ba77484d68baea5c7092f01826bbbd92 Mon Sep 17 00:00:00 2001 From: ClemensLinnhoff Date: Mon, 26 Feb 2024 10:17:55 +0100 Subject: [PATCH 032/113] Change FCW to forward collision warning Signed-off-by: ClemensLinnhoff --- osi_hostvehicledata.proto | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osi_hostvehicledata.proto b/osi_hostvehicledata.proto index 9594e8e68..026de2a7e 100644 --- a/osi_hostvehicledata.proto +++ b/osi_hostvehicledata.proto @@ -584,7 +584,7 @@ message HostVehicleData STATE_AVAILABLE = 4; // The function is available but conditions have not caused it to be - // triggered, for example, no vehicles in front to trigger a FCW. + // triggered, for example, no vehicles in front to trigger a forward collision warning. // STATE_STANDBY = 5; From 78ac176d9efa5264707b6c40349e4db47bd8813e Mon Sep 17 00:00:00 2001 From: ClemensLinnhoff Date: Mon, 26 Feb 2024 10:19:54 +0100 Subject: [PATCH 033/113] Change grey to gray in comments Signed-off-by: ClemensLinnhoff --- osi_common.proto | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/osi_common.proto b/osi_common.proto index b0e0bcd6c..73c1f464c 100644 --- a/osi_common.proto +++ b/osi_common.proto @@ -673,7 +673,7 @@ message SpatialSignalStrength // message ColorDescription { - // Greyscale color model + // Grayscale color model // optional ColorGrey grey = 1; @@ -699,13 +699,13 @@ message ColorDescription } // -// \brief Greyscale color model +// \brief Grayscale color model // -// ColorGrey defines a greyscale. +// ColorGrey defines a grayscale. // message ColorGrey { - // Definition of a greyscale + // Definition of a grayscale // // Range: [0,1] // From 5608a4927d5a035d690c569db3386ddb343c4473 Mon Sep 17 00:00:00 2001 From: ClemensLinnhoff Date: Mon, 26 Feb 2024 10:20:30 +0100 Subject: [PATCH 034/113] Fixed another grey Signed-off-by: ClemensLinnhoff --- osi_featuredata.proto | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osi_featuredata.proto b/osi_featuredata.proto index 5856e1f87..402869366 100644 --- a/osi_featuredata.proto +++ b/osi_featuredata.proto @@ -929,7 +929,7 @@ message CameraDetection // COLOR_BLACK = 2; - // Shape with grey color. + // Shape with gray color. // COLOR_GREY = 3; From 750ca988b04b5723e189a218866aa2c4745a0843 Mon Sep 17 00:00:00 2001 From: ClemensLinnhoff Date: Mon, 26 Feb 2024 10:24:23 +0100 Subject: [PATCH 035/113] Added grayscale to custom words Signed-off-by: ClemensLinnhoff --- .github/spelling_custom_words_en_US.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/spelling_custom_words_en_US.txt b/.github/spelling_custom_words_en_US.txt index 7f7f5fa70..9d00d4057 100644 --- a/.github/spelling_custom_words_en_US.txt +++ b/.github/spelling_custom_words_en_US.txt @@ -146,6 +146,7 @@ gesetze github glichkeit GNSS +grayscale gridded Groessen GroundTruthInit From 8a25677b8ccfb52acf04743a4d2fe3445b011fe9 Mon Sep 17 00:00:00 2001 From: ClemensLinnhoff Date: Mon, 26 Feb 2024 11:32:13 +0100 Subject: [PATCH 036/113] Added antecessor to custom word list Signed-off-by: ClemensLinnhoff --- .github/spelling_custom_words_en_US.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/spelling_custom_words_en_US.txt b/.github/spelling_custom_words_en_US.txt index 9d00d4057..a88e44be9 100644 --- a/.github/spelling_custom_words_en_US.txt +++ b/.github/spelling_custom_words_en_US.txt @@ -10,6 +10,7 @@ Anfang Anglais anlage Anlieger +antecessor arg asam atsc From 0f6d42401043886968e84799c0150148d3e7ecf4 Mon Sep 17 00:00:00 2001 From: "Pierre R. Mai" Date: Mon, 26 Feb 2024 12:37:37 +0100 Subject: [PATCH 037/113] Add aliases for typos in enum values Signed-off-by: Pierre R. Mai --- osi_featuredata.proto | 10 ++++++++++ osi_object.proto | 22 +++++++++++++++++++++- tests/test_invalid_enum.py | 6 ++++++ 3 files changed, 37 insertions(+), 1 deletion(-) diff --git a/osi_featuredata.proto b/osi_featuredata.proto index 402869366..c82c3c727 100644 --- a/osi_featuredata.proto +++ b/osi_featuredata.proto @@ -916,6 +916,10 @@ message CameraDetection // enum Color { + // Allow aliases in enum + // + option allow_alias = true; + // Color of the shape is unknown (must not be used in ground // truth). // @@ -931,6 +935,12 @@ message CameraDetection // Shape with gray color. // + COLOR_GRAY = 3; + + // Shape with gray color. + // + // \note Deprecated variant spelling of COLOR_GRAY + // COLOR_GREY = 3; // Shape with white color. diff --git a/osi_object.proto b/osi_object.proto index cf59d6bc7..a40873785 100644 --- a/osi_object.proto +++ b/osi_object.proto @@ -223,6 +223,10 @@ message StationaryObject // enum Material { + // Allow aliases in enum + // + option allow_alias = true; + // Type of the material is unknown (must not be used in ground // truth). // @@ -254,6 +258,12 @@ message StationaryObject // Glass structure. // + MATERIAL_GLASS = 7; + + // Glass structure. + // + // \note Deprecated variant spelling of MATERIAL_GLASS + // MATERIAL_GLAS = 7; // Mud structure. @@ -303,6 +313,10 @@ message StationaryObject // enum Color { + // Allow aliases in enum + // + option allow_alias = true; + // Color is unknown (must not be used in ground truth). // COLOR_UNKNOWN = 0; @@ -339,7 +353,13 @@ message StationaryObject // COLOR_BLACK = 8; - // GREY. + // GRAY. + // + COLOR_GRAY = 9; + + // GRAY. + // + // \note Deprecated variant spelling of COLOR_GRAY // COLOR_GREY = 9; diff --git a/tests/test_invalid_enum.py b/tests/test_invalid_enum.py index 01d9ff9e9..7e7823f0f 100644 --- a/tests/test_invalid_enum.py +++ b/tests/test_invalid_enum.py @@ -25,6 +25,9 @@ def test_correct_enum_name(self): if matchComment is not None: statement = line[: matchComment.start()] comment = line[matchComment.end() :] + elif re.search("option allow_alias", line): + statement = "" + comment = "" else: statement = line comment = "" @@ -123,6 +126,9 @@ def test_invalid_enum(self): if matchComment is not None: statement = line[: matchComment.start()] comment = line[matchComment.end() :] + elif re.search("option allow_alias", line): + statement = "" + comment = "" else: statement = line comment = "" From 2a4902a019b1d59e9b2c30aa8638bd2b616b2651 Mon Sep 17 00:00:00 2001 From: Nicholas Dunning Date: Tue, 6 Dec 2022 16:54:47 +0100 Subject: [PATCH 038/113] Add BoundingBox section Signed-off-by: Nicholas Dunning --- osi_common.proto | 153 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 153 insertions(+) diff --git a/osi_common.proto b/osi_common.proto index 73c1f464c..a7c48c725 100644 --- a/osi_common.proto +++ b/osi_common.proto @@ -387,6 +387,125 @@ message LogicalLaneAssignment optional double angle_to_lane = 4; } +// \brief A bounding box containing a sub-section of a object. +// +// A bounding box representing a sub-section of it's parents overall dimension, +// either that of a \c MovingObject or \c StationaryObject . +// +// The parent frame of the \c BoundingBox is not relative to the parent object +// it is associated to, but in the same parent frame as the parent object. +// +message BoundingBox +{ + // The 3D dimensions of the bounding box. + // + optional Dimension3d dimension = 1; + + // The 3D position of the bounding box. + // + // \note The position should be within the same coordinate frame as it's + // parent, not relative to coordinate frame of the parent object. The + // position becomes global/absolute if the parent frame is inertial + // (all parent frames up to ground truth). + // + optional Vector3d position = 2; + + // The 3D orientation of the bounding box. + // + // \note The orientation should be within the same coordinate frame as it's + // parent, not relative to coordinate frame of the parent object. The + // orientation becomes global/absolute if the parent frame is inertial + // (all parent frames up to ground truth). + // + optional Orientation3d orientation = 3; + + // The type of object contained in the bounding box. + // + optional Type contained_object_type = 4; + + // Opaque reference of an associated 3D model of the bounding box. + // + // \note It is implementation-specific how model_references are resolved to + // 3d models. This means the coordinate system, model origin, and model + // orientation are also implementation-specific. + // + optional string model_reference = 5; + + // Definition of different types of object contained within the bounding box + // + enum Type + { + // Object of unknown type (must not be used in ground truth). + // + TYPE_UNKNOWN = 0; + + // Any other type of object. + // + TYPE_OTHER = 1; + + // The main chassis of a vehicle. + // + TYPE_CHASSIS = 2; + + // The door of a vehicle. + // + // \note A door may extend beyond the dimension of the parent when in + // an open state. A closed door must be within the original dimension. + // + TYPE_DOOR = 3; + + // The side mirror of a vehicle. + // + // \note A side mirror may extend beyond the dimension of the parent. + // + TYPE_SIDE_MIRROR = 4; + + // Additional cargo attached to the a vehicle which is temporarily + // attached. + // + // \note Cargo may extend beyond the dimension of the parent. + // + TYPE_CARGO = 5; + + // The wheel of a vehicle. + // + // \note A wheel may extend beyond the dimension of the parent. + // + // \note For more detailed information about the wheels of an object, + // please refer to \c MovingObject/VehicleAttributes/WheelData . + // + TYPE_WHEEL = 6; + + // The torso section of a person or animal. + // + TYPE_TORSO = 7; + + // An external limb of a person or animal. + // + TYPE_LIMB = 8; + + // The head of a person or animal. + // + TYPE_HEAD = 9; + + // The trunk section of a tree. + // + TYPE_TREE_TRUNK = 10; + + // The crown of a tree, usually encompassing the branches and leaves. + // + TYPE_TREE_CROWN = 11; + + // The vertical pole of a street light. + // + TYPE_STREET_LIGHT_POLE = 12; + + // The horizontal arm of a street light. + // + TYPE_STREET_LIGHT_ARM = 13; + } +} + // // \brief The base attributes of a stationary object or entity. // @@ -447,6 +566,23 @@ message BaseStationary // The polygon is defined counter-clockwise. // repeated Vector2d base_polygon = 4; + + // Sub-divisions of the overall bounding box of the \c BaseStationary object. + // + // The bounding box sections can include separate parts on partially-opaque + // objects such are trees with a distinction between trunk and crown. + // + // \note When one or more \c BoundingBox s are associated to a + // \c BaseStationary , the expectation is that all sections are contained + // within the bounds of the \c #dimension . + // + // \note It is also expcted that when using \c #bounding_box_section , + // anyone consuming this data has the guarantee that all others parts of + // the \c BaseStationary are covered by a sub-section, such that the + // guarentee is that the remaining area of the objects dimension is + // represented by space where no physical collisions could be detected. + // + repeated BoundingBox bounding_box_section = 5; } // @@ -569,6 +705,23 @@ message BaseMoving // The polygon is defined counter-clockwise. // repeated Vector2d base_polygon = 7; + + // Sub-divisions of the overall bounding box of the \c BaseMoving object. + // + // The bounding box sections can include side mirrors, cargo, etc. for + // vehicles, as well as body-part sections for pedestrians. + // + // \note When one or more \c BoundingBox s are associated to a + // \c BaseMoving , the expectation is that all sections are contained + // within the bounds of the \c #dimension . + // + // \note It is also expcted that when using \c #bounding_box_section , + // anyone consuming this data has the guarantee that all others parts of + // the \c BaseMoving are covered by a sub-section, such that the + // guarentee is that the remaining area of the objects dimension is + // represented by space where no physical collisions could be detected. + // + repeated BoundingBox bounding_box_section = 9; } // From e32e5666985a2466e933ceb70c62b2b5072e6f6e Mon Sep 17 00:00:00 2001 From: Nicholas Dunning Date: Mon, 30 Jan 2023 09:29:28 +0100 Subject: [PATCH 039/113] Add clarity for limbs Signed-off-by: Nicholas Dunning --- osi_common.proto | 2 ++ 1 file changed, 2 insertions(+) diff --git a/osi_common.proto b/osi_common.proto index a7c48c725..e8b510695 100644 --- a/osi_common.proto +++ b/osi_common.proto @@ -482,6 +482,8 @@ message BoundingBox // An external limb of a person or animal. // + // \note Limbs can be sub-divided to increase accuracy, i.e. for upper + // and lower arm/leg sections. TYPE_LIMB = 8; // The head of a person or animal. From 7b24c44a61b8696acd9bfb02c259e9e54430cdd7 Mon Sep 17 00:00:00 2001 From: Thomas Hempen Date: Wed, 17 May 2023 16:47:09 +0200 Subject: [PATCH 040/113] Enhance description for bounding_box_section Add information regarding the handling of side mirrors and the definition of the bounding box. Signed-off-by: Pierre R. Mai --- osi_common.proto | 42 ++++++++++++++++++++---------------------- 1 file changed, 20 insertions(+), 22 deletions(-) diff --git a/osi_common.proto b/osi_common.proto index e8b510695..30b57b455 100644 --- a/osi_common.proto +++ b/osi_common.proto @@ -387,14 +387,17 @@ message LogicalLaneAssignment optional double angle_to_lane = 4; } -// \brief A bounding box containing a sub-section of a object. +// \brief A bounding box description. // // A bounding box representing a sub-section of it's parents overall dimension, -// either that of a \c MovingObject or \c StationaryObject . +// either that of a \c BaseMoving or \c BaseStationary . // // The parent frame of the \c BoundingBox is not relative to the parent object // it is associated to, but in the same parent frame as the parent object. // +// \note The actual bounding box of the object is defined in dimension, position +// and orientation of the \c BaseMoving and \c BaseStationary . +// message BoundingBox { // The 3D dimensions of the bounding box. @@ -448,31 +451,25 @@ message BoundingBox TYPE_CHASSIS = 2; // The door of a vehicle. - // - // \note A door may extend beyond the dimension of the parent when in - // an open state. A closed door must be within the original dimension. // TYPE_DOOR = 3; // The side mirror of a vehicle. // - // \note A side mirror may extend beyond the dimension of the parent. + // \note The side mirror is not included in the actual bounding box of + // the parent object. // TYPE_SIDE_MIRROR = 4; // Additional cargo attached to the a vehicle which is temporarily // attached. - // - // \note Cargo may extend beyond the dimension of the parent. // TYPE_CARGO = 5; // The wheel of a vehicle. // - // \note A wheel may extend beyond the dimension of the parent. - // // \note For more detailed information about the wheels of an object, - // please refer to \c MovingObject/VehicleAttributes/WheelData . + // please refer to \c MovingObject/VehicleAttributes/WheelData. // TYPE_WHEEL = 6; @@ -484,6 +481,7 @@ message BoundingBox // // \note Limbs can be sub-divided to increase accuracy, i.e. for upper // and lower arm/leg sections. + // TYPE_LIMB = 8; // The head of a person or animal. @@ -526,6 +524,9 @@ message BaseStationary // The 3D dimensions of the stationary object (bounding box), e.g. a // landmark. // + // \note The \c #dimension must completely enclose the geometry of the + // \c BaseStationary . + // optional Dimension3d dimension = 1; // The reference point for position and orientation, i.e. the center (x,y,z) @@ -572,13 +573,9 @@ message BaseStationary // Sub-divisions of the overall bounding box of the \c BaseStationary object. // // The bounding box sections can include separate parts on partially-opaque - // objects such are trees with a distinction between trunk and crown. - // - // \note When one or more \c BoundingBox s are associated to a - // \c BaseStationary , the expectation is that all sections are contained - // within the bounds of the \c #dimension . + // objects such as trees with a distinction between trunk and crown. // - // \note It is also expcted that when using \c #bounding_box_section , + // \note It is expected that when using \c #bounding_box_section , // anyone consuming this data has the guarantee that all others parts of // the \c BaseStationary are covered by a sub-section, such that the // guarentee is that the remaining area of the objects dimension is @@ -607,6 +604,9 @@ message BaseMoving { // The 3D dimension of the moving object (its bounding box). // + // \note The \c #dimension must completely enclose the geometry of the + // \c BaseMoving . + // // \note The bounding box does NOT include side mirrors for vehicles. // optional Dimension3d dimension = 1; @@ -614,6 +614,7 @@ message BaseMoving // The reference point for position and orientation: the center (x,y,z) of // the bounding box. // + // optional Vector3d position = 2; // The relative orientation of the moving object w.r.t. its parent frame, @@ -712,16 +713,13 @@ message BaseMoving // // The bounding box sections can include side mirrors, cargo, etc. for // vehicles, as well as body-part sections for pedestrians. - // - // \note When one or more \c BoundingBox s are associated to a - // \c BaseMoving , the expectation is that all sections are contained - // within the bounds of the \c #dimension . // - // \note It is also expcted that when using \c #bounding_box_section , + // \note It is also expected that when using \c #bounding_box_section , // anyone consuming this data has the guarantee that all others parts of // the \c BaseMoving are covered by a sub-section, such that the // guarentee is that the remaining area of the objects dimension is // represented by space where no physical collisions could be detected. + // This does not include the side mirrors. // repeated BoundingBox bounding_box_section = 9; } From c71f9c3005432eae62ea0cd55cfa3821abc6032a Mon Sep 17 00:00:00 2001 From: "Pierre R. Mai" Date: Fri, 16 Jun 2023 11:00:39 +0200 Subject: [PATCH 041/113] Rewording and typo fixes as per discussions Signed-off-by: Pierre R. Mai --- osi_common.proto | 125 ++++++++++++++++++++++++++--------------------- 1 file changed, 68 insertions(+), 57 deletions(-) diff --git a/osi_common.proto b/osi_common.proto index 30b57b455..6208d27f6 100644 --- a/osi_common.proto +++ b/osi_common.proto @@ -387,16 +387,20 @@ message LogicalLaneAssignment optional double angle_to_lane = 4; } -// \brief A bounding box description. +// \brief A bounding box description. // -// A bounding box representing a sub-section of it's parents overall dimension, -// either that of a \c BaseMoving or \c BaseStationary . +// A bounding box representing a sub-section of its parent's overall +// dimension, either that of a \c BaseMoving or \c BaseStationary . // -// The parent frame of the \c BoundingBox is not relative to the parent object -// it is associated to, but in the same parent frame as the parent object. +// The parent frame of the \c BoundingBox is identical to the parent frame +// of the \c MovingObject or \c StationaryObject it is associated to. For +// example, if the parent object coordinates are given relative to the +// global coordinate system, then the \c BoundingBox coordinates are also +// given relative to the global coordinate system. // -// \note The actual bounding box of the object is defined in dimension, position -// and orientation of the \c BaseMoving and \c BaseStationary . +// \note The overall bounding box of the object is still defined using the +// dimension, position and orientation of the \c BaseMoving or +// \c BaseStationary . // message BoundingBox { @@ -406,25 +410,25 @@ message BoundingBox // The 3D position of the bounding box. // - // \note The position should be within the same coordinate frame as it's - // parent, not relative to coordinate frame of the parent object. The - // position becomes global/absolute if the parent frame is inertial + // \note The position should be within the same coordinate frame as + // its parent, not relative to coordinate frame of the parent object. + // The position becomes global/absolute if the parent frame is inertial // (all parent frames up to ground truth). // optional Vector3d position = 2; // The 3D orientation of the bounding box. // - // \note The orientation should be within the same coordinate frame as it's - // parent, not relative to coordinate frame of the parent object. The - // orientation becomes global/absolute if the parent frame is inertial + // \note The orientation should be within the same coordinate frame as + // its parent, not relative to the coordinate frame of the parent object. + // The orientation becomes global/absolute if the parent frame is inertial // (all parent frames up to ground truth). // optional Orientation3d orientation = 3; // The type of object contained in the bounding box. // - optional Type contained_object_type = 4; + optional Type contained_object_type = 4; // Opaque reference of an associated 3D model of the bounding box. // @@ -449,59 +453,59 @@ message BoundingBox // The main chassis of a vehicle. // TYPE_CHASSIS = 2; - + // The door of a vehicle. - // + // TYPE_DOOR = 3; - + // The side mirror of a vehicle. // - // \note The side mirror is not included in the actual bounding box of - // the parent object. - // + // \note The side mirror is not included in the overall bounding box + // of the parent object. + // TYPE_SIDE_MIRROR = 4; - + // Additional cargo attached to the a vehicle which is temporarily // attached. - // + // TYPE_CARGO = 5; - + // The wheel of a vehicle. // // \note For more detailed information about the wheels of an object, // please refer to \c MovingObject/VehicleAttributes/WheelData. - // + // TYPE_WHEEL = 6; - + // The torso section of a person or animal. - // + // TYPE_TORSO = 7; - + // An external limb of a person or animal. - // - // \note Limbs can be sub-divided to increase accuracy, i.e. for upper + // + // \note Limbs can be sub-divided to increase accuracy, i.e. for upper // and lower arm/leg sections. // TYPE_LIMB = 8; - + // The head of a person or animal. - // + // TYPE_HEAD = 9; - + // The trunk section of a tree. - // + // TYPE_TREE_TRUNK = 10; - + // The crown of a tree, usually encompassing the branches and leaves. - // + // TYPE_TREE_CROWN = 11; - + // The vertical pole of a street light. - // + // TYPE_STREET_LIGHT_POLE = 12; - + // The horizontal arm of a street light. - // + // TYPE_STREET_LIGHT_ARM = 13; } } @@ -524,7 +528,7 @@ message BaseStationary // The 3D dimensions of the stationary object (bounding box), e.g. a // landmark. // - // \note The \c #dimension must completely enclose the geometry of the + // \note The \c #dimension must completely enclose the geometry of the // \c BaseStationary . // optional Dimension3d dimension = 1; @@ -575,11 +579,15 @@ message BaseStationary // The bounding box sections can include separate parts on partially-opaque // objects such as trees with a distinction between trunk and crown. // - // \note It is expected that when using \c #bounding_box_section , - // anyone consuming this data has the guarantee that all others parts of - // the \c BaseStationary are covered by a sub-section, such that the - // guarentee is that the remaining area of the objects dimension is - // represented by space where no physical collisions could be detected. + // \note The bounding box sub-divisions can extend beyond the overall + // bounding box, however no actual geometry must reside outside of the + // overall bounding box. + // + // \note If any sub-divisions are provided, then they must cover all + // occupied space of the overall bounding box. In other words, a consumer + // of this data is guaranteed that any part of the overall bounding box + // that is not covered by any sub-division is free of physical objects, + // and thus no collisions can occur there. // repeated BoundingBox bounding_box_section = 5; } @@ -604,8 +612,8 @@ message BaseMoving { // The 3D dimension of the moving object (its bounding box). // - // \note The \c #dimension must completely enclose the geometry of the - // \c BaseMoving . + // \note The \c #dimension must completely enclose the geometry of the + // \c BaseMoving with the exception of the side mirrors for vehicles. // // \note The bounding box does NOT include side mirrors for vehicles. // @@ -614,7 +622,6 @@ message BaseMoving // The reference point for position and orientation: the center (x,y,z) of // the bounding box. // - // optional Vector3d position = 2; // The relative orientation of the moving object w.r.t. its parent frame, @@ -711,15 +718,19 @@ message BaseMoving // Sub-divisions of the overall bounding box of the \c BaseMoving object. // - // The bounding box sections can include side mirrors, cargo, etc. for - // vehicles, as well as body-part sections for pedestrians. - // - // \note It is also expected that when using \c #bounding_box_section , - // anyone consuming this data has the guarantee that all others parts of - // the \c BaseMoving are covered by a sub-section, such that the - // guarentee is that the remaining area of the objects dimension is - // represented by space where no physical collisions could be detected. - // This does not include the side mirrors. + // The bounding box sections can include side mirrors, cargo, etc. for + // vehicles, as well as body-part sections for pedestrians. Note that for + // more precise pedestrian information \c PedestrianAttributes can be used. + // + // \note The bounding box sub-divisions can extend beyond the overall + // bounding box, however no actual geometry must reside outside of the + // overall bounding box, with the specific exception of the side mirrors. + // + // \note If any sub-divisions are provided, then they must cover all + // occupied space of the overall bounding box. In other words, a consumer + // of this data is guaranteed that any part of the overall bounding box + // that is not covered by any sub-division is free of physical objects, + // and thus no collisions can occur there. // repeated BoundingBox bounding_box_section = 9; } From 1ab843279dd801cf689fe011722c945f04828fca Mon Sep 17 00:00:00 2001 From: Thomas Hempen Date: Mon, 29 Jan 2024 07:19:35 +0100 Subject: [PATCH 042/113] Updated the BoundingBox message. - Clarified the position definition. - Added a "other_object_type" sting to define object types, which are not part of the Type definition enum. - Reduced the Type field, because of compatibility reason. There is a general approach to harmonize object type definitions. So the definition should not get in conflict to that approach. Signed-off-by: Thomas Hempen --- osi_common.proto | 73 +++++++++--------------------------------------- 1 file changed, 13 insertions(+), 60 deletions(-) diff --git a/osi_common.proto b/osi_common.proto index 6208d27f6..db036d8af 100644 --- a/osi_common.proto +++ b/osi_common.proto @@ -408,7 +408,8 @@ message BoundingBox // optional Dimension3d dimension = 1; - // The 3D position of the bounding box. + // The 3D position of the bounding box. The position is the center + // of the bounding box and the pivot for the \c dimension and \c orientation. // // \note The position should be within the same coordinate frame as // its parent, not relative to coordinate frame of the parent object. @@ -430,16 +431,26 @@ message BoundingBox // optional Type contained_object_type = 4; + // Another type of object contained in the bounding box + // + // This field shall only be used if \c contained_object_type is TYPE_OTHER + // and the object type is not defined withing \c contained_object_type. + // + optional string other_object_type = 5; + // Opaque reference of an associated 3D model of the bounding box. // // \note It is implementation-specific how model_references are resolved to // 3d models. This means the coordinate system, model origin, and model // orientation are also implementation-specific. // - optional string model_reference = 5; + optional string model_reference = 6; // Definition of different types of object contained within the bounding box // + // \note This enum field is mainly a placeholder to be extended in the future. + // feel free to suggest type definitions for future releases. + // enum Type { // Object of unknown type (must not be used in ground truth). @@ -449,64 +460,6 @@ message BoundingBox // Any other type of object. // TYPE_OTHER = 1; - - // The main chassis of a vehicle. - // - TYPE_CHASSIS = 2; - - // The door of a vehicle. - // - TYPE_DOOR = 3; - - // The side mirror of a vehicle. - // - // \note The side mirror is not included in the overall bounding box - // of the parent object. - // - TYPE_SIDE_MIRROR = 4; - - // Additional cargo attached to the a vehicle which is temporarily - // attached. - // - TYPE_CARGO = 5; - - // The wheel of a vehicle. - // - // \note For more detailed information about the wheels of an object, - // please refer to \c MovingObject/VehicleAttributes/WheelData. - // - TYPE_WHEEL = 6; - - // The torso section of a person or animal. - // - TYPE_TORSO = 7; - - // An external limb of a person or animal. - // - // \note Limbs can be sub-divided to increase accuracy, i.e. for upper - // and lower arm/leg sections. - // - TYPE_LIMB = 8; - - // The head of a person or animal. - // - TYPE_HEAD = 9; - - // The trunk section of a tree. - // - TYPE_TREE_TRUNK = 10; - - // The crown of a tree, usually encompassing the branches and leaves. - // - TYPE_TREE_CROWN = 11; - - // The vertical pole of a street light. - // - TYPE_STREET_LIGHT_POLE = 12; - - // The horizontal arm of a street light. - // - TYPE_STREET_LIGHT_ARM = 13; } } From 6e093999603a2942d51c851ce4129f6c59035a84 Mon Sep 17 00:00:00 2001 From: Thomas Hempen Date: Thu, 15 Feb 2024 16:07:34 +0100 Subject: [PATCH 043/113] Reworked the Type fields. Signed-off-by: Thomas Hempen --- osi_common.proto | 35 +++++++++++++++++++++++++---------- 1 file changed, 25 insertions(+), 10 deletions(-) diff --git a/osi_common.proto b/osi_common.proto index db036d8af..5a38c08dc 100644 --- a/osi_common.proto +++ b/osi_common.proto @@ -431,13 +431,6 @@ message BoundingBox // optional Type contained_object_type = 4; - // Another type of object contained in the bounding box - // - // This field shall only be used if \c contained_object_type is TYPE_OTHER - // and the object type is not defined withing \c contained_object_type. - // - optional string other_object_type = 5; - // Opaque reference of an associated 3D model of the bounding box. // // \note It is implementation-specific how model_references are resolved to @@ -448,9 +441,6 @@ message BoundingBox // Definition of different types of object contained within the bounding box // - // \note This enum field is mainly a placeholder to be extended in the future. - // feel free to suggest type definitions for future releases. - // enum Type { // Object of unknown type (must not be used in ground truth). @@ -460,6 +450,31 @@ message BoundingBox // Any other type of object. // TYPE_OTHER = 1; + + // The main structure of an object, e.g. a chassis of a vehicle, + // or the central structure of a building, a tree trunk, etc. + // + TYPE_BASE_STRUCTURE = 2; + + // The door of an object. + // + TYPE_DOOR = 3; + + // The side mirror of a vehicle. + // + // \note The side mirror is not included in the overall bounding box + // of the parent object. + // + TYPE_SIDE_MIRROR = 4; + + // Additional, temporarily attached cargo to an object. + // + TYPE_CARGO = 5; + + // An overhanging, integral part of on object, which is not temporarily attached. + // e.g. a tree crown, or a light pole arm. + // + TYPE_PROTRUDING = 6; } } From 2b5149bb69c56d234654dcba41f490917a5936ed Mon Sep 17 00:00:00 2001 From: Thomas Hempen Date: Thu, 15 Feb 2024 16:09:02 +0100 Subject: [PATCH 044/113] Fixed numbering. Signed-off-by: Thomas Hempen --- osi_common.proto | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osi_common.proto b/osi_common.proto index 5a38c08dc..125e8fffc 100644 --- a/osi_common.proto +++ b/osi_common.proto @@ -437,7 +437,7 @@ message BoundingBox // 3d models. This means the coordinate system, model origin, and model // orientation are also implementation-specific. // - optional string model_reference = 6; + optional string model_reference = 5; // Definition of different types of object contained within the bounding box // From 79ee4883ce1de73024cf3fadc794c91b2be505be Mon Sep 17 00:00:00 2001 From: Thomas Hempen Date: Thu, 15 Feb 2024 16:18:52 +0100 Subject: [PATCH 045/113] Changed formatting. Signed-off-by: Thomas Hempen --- osi_common.proto | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/osi_common.proto b/osi_common.proto index 125e8fffc..5d2dbce9a 100644 --- a/osi_common.proto +++ b/osi_common.proto @@ -471,8 +471,8 @@ message BoundingBox // TYPE_CARGO = 5; - // An overhanging, integral part of on object, which is not temporarily attached. - // e.g. a tree crown, or a light pole arm. + // An overhanging, integral part of on object, which is not + // temporarily attached. e.g. a tree crown, or a light pole arm. // TYPE_PROTRUDING = 6; } From e8a5ed0d0de4668ac8927d1c1ac8975c1e307789 Mon Sep 17 00:00:00 2001 From: Thomas Hempen Date: Thu, 15 Feb 2024 16:38:01 +0100 Subject: [PATCH 046/113] Typo correction. Signed-off-by: Thomas Hempen --- osi_common.proto | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osi_common.proto b/osi_common.proto index 5d2dbce9a..30b0fc7f0 100644 --- a/osi_common.proto +++ b/osi_common.proto @@ -472,7 +472,7 @@ message BoundingBox TYPE_CARGO = 5; // An overhanging, integral part of on object, which is not - // temporarily attached. e.g. a tree crown, or a light pole arm. + // temporarily attached, e.g. a tree crown, or a light pole arm. // TYPE_PROTRUDING = 6; } From dab24b14de0c1a01bffa12971e68e2c5b22a38bd Mon Sep 17 00:00:00 2001 From: Thomas Hempen Date: Thu, 15 Feb 2024 16:56:17 +0100 Subject: [PATCH 047/113] Typo corrected. Signed-off-by: Thomas Hempen --- osi_common.proto | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osi_common.proto b/osi_common.proto index 30b0fc7f0..942f77d3c 100644 --- a/osi_common.proto +++ b/osi_common.proto @@ -471,7 +471,7 @@ message BoundingBox // TYPE_CARGO = 5; - // An overhanging, integral part of on object, which is not + // An overhanging, integral part of an object, which is not // temporarily attached, e.g. a tree crown, or a light pole arm. // TYPE_PROTRUDING = 6; From c4338e74eeb4dde304c3ba3663d4d93793e27507 Mon Sep 17 00:00:00 2001 From: Thomas Sedlmayer Date: Mon, 26 Feb 2024 08:52:29 +0100 Subject: [PATCH 048/113] Reorder sub bounding box enums Signed-off-by: Thomas Sedlmayer --- osi_common.proto | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/osi_common.proto b/osi_common.proto index 942f77d3c..4b4109bdd 100644 --- a/osi_common.proto +++ b/osi_common.proto @@ -456,25 +456,25 @@ message BoundingBox // TYPE_BASE_STRUCTURE = 2; + // An overhanging, integral part of an object, which is not + // temporarily attached, e.g. a tree crown, or a light pole arm. + // + TYPE_PROTRUDING_STRUCTURE = 3; + + // Additional, temporarily attached cargo to an object. + // + TYPE_CARGO = 4; + // The door of an object. // - TYPE_DOOR = 3; + TYPE_DOOR = 5; // The side mirror of a vehicle. // // \note The side mirror is not included in the overall bounding box // of the parent object. // - TYPE_SIDE_MIRROR = 4; - - // Additional, temporarily attached cargo to an object. - // - TYPE_CARGO = 5; - - // An overhanging, integral part of an object, which is not - // temporarily attached, e.g. a tree crown, or a light pole arm. - // - TYPE_PROTRUDING = 6; + TYPE_SIDE_MIRROR = 6; } } From 65b814d208083663a5eac53d5ad9dcf2de91f1e8 Mon Sep 17 00:00:00 2001 From: Thomas Hempen Date: Mon, 26 Feb 2024 10:42:47 +0100 Subject: [PATCH 049/113] Updated comments Signed-off-by: Thomas Hempen --- osi_common.proto | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/osi_common.proto b/osi_common.proto index 4b4109bdd..1ea601338 100644 --- a/osi_common.proto +++ b/osi_common.proto @@ -456,8 +456,10 @@ message BoundingBox // TYPE_BASE_STRUCTURE = 2; - // An overhanging, integral part of an object, which is not - // temporarily attached, e.g. a tree crown, or a light pole arm. + // A protruding, integral part of an object, which is not + // temporarily attached, e.g. a tree crown, a light pole arm, or a + // parking house gate. The protruding structure is meant to be an + // additional part to a base structure. // TYPE_PROTRUDING_STRUCTURE = 3; From 5cfed341a730379c9a06af33dc43c02d42ca794c Mon Sep 17 00:00:00 2001 From: Thomas Hempen Date: Mon, 26 Feb 2024 10:45:29 +0100 Subject: [PATCH 050/113] Updated format. Removed invalid tabs. Signed-off-by: Thomas Hempen --- osi_common.proto | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/osi_common.proto b/osi_common.proto index 1ea601338..1bf6a8751 100644 --- a/osi_common.proto +++ b/osi_common.proto @@ -458,8 +458,8 @@ message BoundingBox // A protruding, integral part of an object, which is not // temporarily attached, e.g. a tree crown, a light pole arm, or a - // parking house gate. The protruding structure is meant to be an - // additional part to a base structure. + // parking house gate. The protruding structure is meant to be an + // additional part to a base structure. // TYPE_PROTRUDING_STRUCTURE = 3; From 7e81917bbc0fd11b3393a8f453cdee8103527795 Mon Sep 17 00:00:00 2001 From: "Pierre R. Mai" Date: Mon, 26 Feb 2024 13:38:22 +0100 Subject: [PATCH 051/113] Add explicit list of doors for vehicles Signed-off-by: Pierre R. Mai --- osi_common.proto | 3 +++ 1 file changed, 3 insertions(+) diff --git a/osi_common.proto b/osi_common.proto index 1bf6a8751..843ffcef1 100644 --- a/osi_common.proto +++ b/osi_common.proto @@ -469,6 +469,9 @@ message BoundingBox // The door of an object. // + // For vehicles, this includes driver and passenger doors, trunk + // and front hoods, and fuel or charging port covers. + // TYPE_DOOR = 5; // The side mirror of a vehicle. From 37163b6c14c9dcb3e8686a2de30baf0914e8ad76 Mon Sep 17 00:00:00 2001 From: "Pierre R. Mai" Date: Fri, 12 Jan 2024 13:41:15 +0100 Subject: [PATCH 052/113] Update github actions for release workflow Signed-off-by: Pierre R. Mai --- .github/workflows/release.yml | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 541186c34..c68183981 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -17,7 +17,7 @@ jobs: steps: # Check out the GitHub repository - name: Checkout interface - uses: actions/checkout@v3 + uses: actions/checkout@v4 with: path: dist/open-simulation-interface # Set the version variable based on the latest tag (could be replaced with github-internal predefined variable?) @@ -66,7 +66,7 @@ jobs: steps: # Check out the Antora generator - name: Checkout Antora generator - uses: actions/checkout@v3 + uses: actions/checkout@v4 with: repository: OpenSimulationInterface/osi-antora-generator path: antora @@ -94,7 +94,7 @@ jobs: args: antora.sh # Upload the created artifact for later jobs to use - name: Upload artifact - uses: actions/upload-artifact@v3 + uses: actions/upload-artifact@v4 with: name: antora path: antora/site @@ -107,19 +107,19 @@ jobs: steps: # Check out the repository (again) - name: Checkout interface - uses: actions/checkout@v3 + uses: actions/checkout@v4 with: path: dist/open-simulation-interface_${{needs.setup.outputs.output1}} # Check out the sensor model packaging repo - name: Checkout sensor model packaging - uses: actions/checkout@v3 + uses: actions/checkout@v4 with: repository: OpenSimulationInterface/osi-sensor-model-packaging path: dist/osi-sensor-model-packaging fetch-depth: 0 # Retrieve the Antora artifact from the previous job - name: Retrieve Antora artifact - uses: actions/download-artifact@v3 + uses: actions/download-artifact@v4 with: name: antora path: dist/ASAM_OSI_Standard_${{needs.setup.outputs.output1}}/ @@ -154,13 +154,13 @@ jobs: mv osi-sensor-model-packaging osi-sensor-model-packaging_${{ env.OSMP_VERSION }} # Package all collected deliverables - name: Zip Release - uses: TheDoctor0/zip-release@0.6.2 + uses: TheDoctor0/zip-release@0.7.6 with: filename: ASAM_OSI_${{needs.setup.outputs.output1}}.zip directory: dist # Upload the created artifact for the publish job - name: Upload artifact - uses: actions/upload-artifact@v3 + uses: actions/upload-artifact@v4 with: name: deliverables path: dist/ASAM_OSI_${{needs.setup.outputs.output1}}.zip @@ -173,7 +173,7 @@ jobs: steps: # Retrieve the previously uploaded deliverables artifact - name: Retrieve previous artifacts - uses: actions/download-artifact@v3 + uses: actions/download-artifact@v4 with: name: deliverables # Add the new zip file with the deliverables to the respective release From 803c24e2d64c4ecef721ad255cfc1459391679a2 Mon Sep 17 00:00:00 2001 From: "Pierre R. Mai" Date: Fri, 8 Mar 2024 16:46:39 +0100 Subject: [PATCH 053/113] Also fix remaining outdated actions in other workflows Signed-off-by: Pierre R. Mai --- .github/workflows/antora-generator.yml | 2 +- .github/workflows/protobuf.yml | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/.github/workflows/antora-generator.yml b/.github/workflows/antora-generator.yml index 251478266..6e38c9126 100644 --- a/.github/workflows/antora-generator.yml +++ b/.github/workflows/antora-generator.yml @@ -19,7 +19,7 @@ jobs: steps: - name: Trigger generator if: ${{ env.MUP_KEY != '' }} - uses: peter-evans/repository-dispatch@v2 + uses: peter-evans/repository-dispatch@v3 with: token: ${{ secrets.MACHINE_USER_PAT }} event-type: antora-build-trigger diff --git a/.github/workflows/protobuf.yml b/.github/workflows/protobuf.yml index 8bd4c37cc..cce1a59fd 100644 --- a/.github/workflows/protobuf.yml +++ b/.github/workflows/protobuf.yml @@ -13,9 +13,9 @@ on: jobs: spellcheck: name: Spellcheck - runs-on: ubuntu-latest + runs-on: ubuntu-22.04 steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - uses: rojopolis/spellcheck-github-actions@0.36.0 name: Spellcheck with: @@ -50,7 +50,7 @@ jobs: - name: Cache Dependencies id: cache-depends - uses: actions/cache@v3 + uses: actions/cache@v4 with: path: protobuf-${{ env.PROTOBUF_VERSION }} key: ${{ runner.os }}-v2-depends @@ -147,7 +147,7 @@ jobs: - name: Cache Dependencies id: cache-depends - uses: actions/cache@v3 + uses: actions/cache@v4 with: path: protobuf-${{ env.PROTOBUF_VERSION }} key: ${{ runner.os }}-v2-depends From 5e06e287ece98348b550e8f4def569c850a3c291 Mon Sep 17 00:00:00 2001 From: "Pierre R. Mai" Date: Mon, 4 Dec 2023 12:19:27 +0100 Subject: [PATCH 054/113] Add check that all proto files are included in build Signed-off-by: Pierre R. Mai --- .github/workflows/protobuf.yml | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/.github/workflows/protobuf.yml b/.github/workflows/protobuf.yml index cce1a59fd..cd895d5b3 100644 --- a/.github/workflows/protobuf.yml +++ b/.github/workflows/protobuf.yml @@ -32,6 +32,11 @@ jobs: with: submodules: true + - name: Check Build Setup + run: | + ( result=0 ; for f in *.proto ; do grep -wq "$f" CMakeLists.txt || { echo "Missing $f in CMakeLists.txt" && let "result++"; } ; done ; exit $result ) + ( result=0 ; for f in *.proto ; do grep -q '"'$f'"' setup.py || { echo "Missing $f in setup.py" && let "result++"; } ; done ; exit $result ) + - name: Setup Python uses: actions/setup-python@v5 with: From c45f95ec6381ff225664adfe6ee07aba77c277a6 Mon Sep 17 00:00:00 2001 From: Jonas Date: Sun, 25 Feb 2024 19:29:26 +0100 Subject: [PATCH 055/113] feat: Add virtual detection area Signed-off-by: Jonas --- osi_common.proto | 12 ++++++++++++ osi_sensordata.proto | 19 +++++++++++++++++++ 2 files changed, 31 insertions(+) diff --git a/osi_common.proto b/osi_common.proto index 843ffcef1..7db75ca7a 100644 --- a/osi_common.proto +++ b/osi_common.proto @@ -1089,3 +1089,15 @@ message KeyValuePair // optional string value = 2; } + +// +// \brief Polygon in 3 dimensions +// +// A polygon in 3 dimensions which contains a list of vertices. +// +message Polygon3d +{ + // A list of vertices + // + repeated Vector3d vertex = 1; +} diff --git a/osi_sensordata.proto b/osi_sensordata.proto index 523cb4cfb..7dbc838db 100644 --- a/osi_sensordata.proto +++ b/osi_sensordata.proto @@ -313,4 +313,23 @@ message SensorData // in cartesian coordinates. // optional LogicalDetectionData logical_detection_data = 27; + + // + // \brief Virtual detection area of a sensor + // + // The virtual detection area describes the area the sensor can see in a best case scenario + // where no occlusion or other statistical effects are considered. It is described by a set + // of polygons. + // + message VirtualDetectionArea + { + // List of polygons. Each polygon represents a surface of the virtual detection area + // and is given with respect to the virtual sensor coordinate system. + // + repeated Polygon3d polygon = 1; + } + + // Virtual detection area of the sensor + // + optional VirtualDetectionArea virtual_detection_area = 28; } From 14593d65f7a637ac52eb12c8821c0634966c5c4d Mon Sep 17 00:00:00 2001 From: "Pierre R. Mai" Date: Mon, 25 Mar 2024 11:20:17 +0100 Subject: [PATCH 056/113] Apply suggestions from code review Signed-off-by: Pierre R. Mai --- osi_sensordata.proto | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/osi_sensordata.proto b/osi_sensordata.proto index 7dbc838db..18df69230 100644 --- a/osi_sensordata.proto +++ b/osi_sensordata.proto @@ -317,9 +317,13 @@ message SensorData // // \brief Virtual detection area of a sensor // - // The virtual detection area describes the area the sensor can see in a best case scenario - // where no occlusion or other statistical effects are considered. It is described by a set - // of polygons. + // The virtual detection area describes the nominal area the sensor is capable of covering + // in its current operating mode, without taking occlusion or other statistical effects into account. + // This information can be used for visualization or other development purposes as a rough guide + // to nominal sensor performance. + // + // It is described by a set of polygons in cartesian coordinates as a pragmatic approximation for + // the rough shapes expected. // message VirtualDetectionArea { From a286b38e545cf44db071e68a5e73fabaa046429b Mon Sep 17 00:00:00 2001 From: "Pierre R. Mai" Date: Wed, 28 Feb 2024 16:46:55 +0100 Subject: [PATCH 057/113] Modernize python build setup, protoc dependency This moves most meta-data to pyproject.toml, automates the version handling and makes it available at runtime, depends on protoc via the protoc-wheel-0 package, makes sdist and bdist distributions work correctly, and removes dependencies that are not build dependencies, but rather used only in CI. Signed-off-by: Pierre R. Mai --- .github/workflows/protobuf.yml | 30 ++++-- .gitignore | 2 - MANIFEST.in | 1 + pyproject.toml | 32 ++++++ ...ents_develop.txt => requirements_tests.txt | 2 - setup.py | 99 ++++++++++++------- 6 files changed, 116 insertions(+), 50 deletions(-) create mode 100644 MANIFEST.in create mode 100644 pyproject.toml rename requirements_develop.txt => requirements_tests.txt (56%) diff --git a/.github/workflows/protobuf.yml b/.github/workflows/protobuf.yml index cd895d5b3..d236e0f06 100644 --- a/.github/workflows/protobuf.yml +++ b/.github/workflows/protobuf.yml @@ -45,10 +45,12 @@ jobs: - name: Install Python Dependencies run: | python -m pip install --upgrade pip - python -m pip install -r requirements_develop.txt + python -m pip install build + python -m pip install -r requirements_tests.txt - name: Check black format - run: black --check --diff . + run: | + black --check --diff . - name: Install Doxygen run: sudo apt-get install doxygen graphviz @@ -88,10 +90,14 @@ jobs: - name: Prepare C++ Build run: mkdir build - # Versioning - - name: Get versioning + - name: Add Development Version Suffix + if: ${{ !startsWith(github.ref, 'refs/tags') }} + run: | + echo "VERSION_SUFFIX = .dev`date -u '+%Y%m%d%H%M%S'`" >> VERSION + + - name: Get git Version id: get_version - run: echo "VERSION=$(git describe --always)" >> $GITHUB_OUTPUT + run: echo "VERSION=$(git describe --tags --always)" >> $GITHUB_OUTPUT - name: Prepare Documentation Build run: | @@ -108,7 +114,7 @@ jobs: run: cmake --build . --config Release -j 4 - name: Build Python - run: python setup.py build && python setup.py sdist + run: python -m build - name: Install Python run: python -m pip install . @@ -148,7 +154,10 @@ jobs: python-version: '3.8' - name: Install Python Dependencies - run: python -m pip install --upgrade pip setuptools wheel pyyaml + run: | + python -m pip install --upgrade pip + python -m pip install build + python -m pip install -r requirements_tests.txt - name: Cache Dependencies id: cache-depends @@ -187,6 +196,11 @@ jobs: bash convert-to-proto3.sh rm *.pb2 + - name: Add Development Version Suffix + if: ${{ !startsWith(github.ref, 'refs/tags') }} + run: | + echo "VERSION_SUFFIX = .dev`date -u '+%Y%m%d%H%M%S'`" >> VERSION + - name: Configure C++ Build working-directory: build run: cmake ${{ env.PROTOBUF_VARIANT =='' && '-DCMAKE_CXX_STANDARD=17' }} .. @@ -196,7 +210,7 @@ jobs: run: cmake --build . --config Release -j 4 - name: Build Python - run: python setup.py build && python setup.py sdist + run: python -m build - name: Install Python run: python -m pip install . diff --git a/.gitignore b/.gitignore index 2076b7c5d..e29f907d0 100644 --- a/.gitignore +++ b/.gitignore @@ -20,8 +20,6 @@ build cmake_install.cmake install_manifest.txt osi_version.proto -version.py -pyproject.toml compile_commands.json diff --git a/MANIFEST.in b/MANIFEST.in new file mode 100644 index 000000000..ceeea233f --- /dev/null +++ b/MANIFEST.in @@ -0,0 +1 @@ +include VERSION diff --git a/pyproject.toml b/pyproject.toml new file mode 100644 index 000000000..17025a2d1 --- /dev/null +++ b/pyproject.toml @@ -0,0 +1,32 @@ +[build-system] +requires = [ + "setuptools", + "wheel", + "protoc-wheel-0==24.4", +] +build-backend = "setuptools.build_meta" + +[project] +name = "open-simulation-interface" +description = "ASAM Open Simulation Interface Python Bindings." +authors = [ + {name = "ASAM Open Simulation Interface Project", email = "osi@asam.net"}, +] +maintainers = [ + {name = "ASAM Open Simulation Interface Project", email = "osi@asam.net"}, +] +dependencies = [ + "protobuf>=4.24.4", +] + +license = {file = "LICENSE"} +readme = "README.md" +classifiers = [ + "License :: OSI Approved :: Mozilla Public License 2.0 (MPL 2.0)", +] +dynamic = ["version"] + +[project.urls] +Homepage = "https://github.com/OpenSimulationInterface/open-simulation-interface" +Repository = "https://github.com/OpenSimulationInterface/open-simulation-interface.git" +"Bug Tracker" = "https://github.com/OpenSimulationInterface/open-simulation-interface/issues" diff --git a/requirements_develop.txt b/requirements_tests.txt similarity index 56% rename from requirements_develop.txt rename to requirements_tests.txt index 5777ec27c..43e06de0a 100644 --- a/requirements_develop.txt +++ b/requirements_tests.txt @@ -1,4 +1,2 @@ -setuptools -wheel pyyaml black==23.12.1 diff --git a/setup.py b/setup.py index cad557993..06014faaa 100644 --- a/setup.py +++ b/setup.py @@ -7,38 +7,41 @@ import re from distutils.spawn import find_executable -# setuptool is dependend on wheel package from setuptools import setup +from setuptools.command.sdist import sdist from setuptools.command.build_py import build_py -# configure the version number -from shutil import copyfile - -copyfile("VERSION", "version.py") -from version import * +# protoc +from protoc import PROTOC_EXE -with open("osi_version.proto.in", "rt") as fin: - with open("osi_version.proto", "wt") as fout: - for line in fin: - lineConfigured = line.replace("@VERSION_MAJOR@", str(VERSION_MAJOR)) - lineConfigured = lineConfigured.replace( - "@VERSION_MINOR@", str(VERSION_MINOR) - ) - lineConfigured = lineConfigured.replace( - "@VERSION_PATCH@", str(VERSION_PATCH) - ) - fout.write(lineConfigured) +# configure the version number +VERSION_MAJOR = None +VERSION_MINOR = None +VERSION_PATCH = None +VERSION_SUFFIX = None +with open("VERSION", "rt") as versionin: + for line in versionin: + if line.startswith("VERSION_MAJOR"): + VERSION_MAJOR = int(line.split("=")[1].strip()) + if line.startswith("VERSION_MINOR"): + VERSION_MINOR = int(line.split("=")[1].strip()) + if line.startswith("VERSION_PATCH"): + VERSION_PATCH = int(line.split("=")[1].strip()) + if line.startswith("VERSION_SUFFIX"): + VERSION_SUFFIX = line.split("=")[1].strip() package_name = "osi3" package_path = os.path.join(os.getcwd(), package_name) -class GenerateProtobufCommand(build_py): +class ProtobufGenerator: @staticmethod def find_protoc(): """Locates protoc executable""" - if "PROTOC" in os.environ and os.path.exists(os.environ["PROTOC"]): + if os.path.exists(PROTOC_EXE): + protoc = PROTOC_EXE + elif "PROTOC" in os.environ and os.path.exists(os.environ["PROTOC"]): protoc = os.environ["PROTOC"] else: protoc = find_executable("protoc") @@ -89,7 +92,19 @@ def find_protoc(): """ Generate Protobuf Messages """ - def run(self): + def generate(self): + sys.stdout.write("Generating Protobuf Version Message\n") + with open("osi_version.proto.in", "rt") as fin: + with open("osi_version.proto", "wt") as fout: + for line in fin: + lineConfigured = line.replace("@VERSION_MAJOR@", str(VERSION_MAJOR)) + lineConfigured = lineConfigured.replace( + "@VERSION_MINOR@", str(VERSION_MINOR) + ) + lineConfigured = lineConfigured.replace( + "@VERSION_PATCH@", str(VERSION_PATCH) + ) + fout.write(lineConfigured) pattern = re.compile('^import "osi_') for source in self.osi_files: with open(source) as src_file: @@ -103,38 +118,46 @@ def run(self): source_path = os.path.join(package_name, source) subprocess.check_call([self.find_protoc(), "--python_out=.", source_path]) + def maybe_generate(self): + if os.path.exists("osi_version.proto.in"): + self.generate() + + +class CustomBuildPyCommand(build_py): + def run(self): + ProtobufGenerator().maybe_generate() build_py.run(self) +class CustomSDistCommand(sdist): + def run(self): + ProtobufGenerator().generate() + sdist.run(self) + + try: os.mkdir(package_path) except Exception: pass try: - open(os.path.join(package_path, "__init__.py"), "a").close() + with open(os.path.join(package_path, "__init__.py"), "wt") as init_file: + init_file.write( + f"__version__ = '{VERSION_MAJOR}.{VERSION_MINOR}.{VERSION_PATCH}{VERSION_SUFFIX or ''}'\n" + ) except Exception: pass setup( - name="open-simulation-interface", - version=str(VERSION_MAJOR) + "." + str(VERSION_MINOR) + "." + str(VERSION_PATCH), - description="A generic interface for the environmental perception of" - "automated driving functions in virtual scenarios.", - author="Carlo van Driesten, Timo Hanke, Nils Hirsenkorn," - "Pilar Garcia-Ramos, Mark Schiementz, Sebastian Schneider", - author_email="Carlo.van-Driesten@bmw.de, Timo.Hanke@bmw.de," - "Nils.Hirsenkorn@tum.de, Pilar.Garcia-Ramos@bmw.de," - "Mark.Schiementz@bmw.de, Sebastian.SB.Schneider@bmw.de", + version=str(VERSION_MAJOR) + + "." + + str(VERSION_MINOR) + + "." + + str(VERSION_PATCH) + + (VERSION_SUFFIX or ""), packages=[package_name], - install_requires=["protobuf"], cmdclass={ - "build_py": GenerateProtobufCommand, + "sdist": CustomSDistCommand, + "build_py": CustomBuildPyCommand, }, - url="https://github.com/OpenSimulationInterface/open-simulation-interface", - license="MPL 2.0", - classifiers=[ - "License :: OSI Approved :: Mozilla Public License 2.0 (MPL 2.0)", - ], - data_files=[("", ["LICENSE"])], ) From 666a1600cb48dc6ed3666fb6773f50e7d58874af Mon Sep 17 00:00:00 2001 From: "Pierre R. Mai" Date: Wed, 28 Feb 2024 20:03:30 +0100 Subject: [PATCH 058/113] Add python distributions to artefacts Signed-off-by: Pierre R. Mai --- .github/workflows/protobuf.yml | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/.github/workflows/protobuf.yml b/.github/workflows/protobuf.yml index d236e0f06..40923dd62 100644 --- a/.github/workflows/protobuf.yml +++ b/.github/workflows/protobuf.yml @@ -130,7 +130,14 @@ jobs: path: doc/html if-no-files-found: error - - name: deploy to gh-pages if push to master branch + - name: Upload Python Distribution + if: ${{ github.event_name == 'pull_request' }} + uses: actions/upload-artifact@v4 + with: + name: python-dist + path: dist/ + + - name: Deploy to gh-pages if push to master branch if: ${{ github.event_name == 'push' && github.ref == 'refs/heads/master' }} uses: peaceiris/actions-gh-pages@v3 with: From 72a26f91f5f48d0c605f557642ebdb2a54d65835 Mon Sep 17 00:00:00 2001 From: "Pierre R. Mai" Date: Thu, 29 Feb 2024 01:10:27 +0100 Subject: [PATCH 059/113] Refactor and include trace file stuff in python package Signed-off-by: Pierre R. Mai --- format/OSITrace.py | 174 ------------------------------ osi3trace/OSITrace.py | 131 ++++++++++++++++++++++ {format => osi3trace}/osi2read.py | 32 +++--- pyproject.toml | 3 + setup.py | 2 +- 5 files changed, 151 insertions(+), 191 deletions(-) delete mode 100644 format/OSITrace.py create mode 100644 osi3trace/OSITrace.py rename {format => osi3trace}/osi2read.py (63%) diff --git a/format/OSITrace.py b/format/OSITrace.py deleted file mode 100644 index cc92f06c7..000000000 --- a/format/OSITrace.py +++ /dev/null @@ -1,174 +0,0 @@ -""" -Module to handle and manage OSI scenarios. -""" -from collections import deque -import time -import lzma -import struct - -from osi3.osi_sensorview_pb2 import SensorView -from osi3.osi_groundtruth_pb2 import GroundTruth -from osi3.osi_sensordata_pb2 import SensorData -import warnings - -warnings.simplefilter("default") - -BUFFER_SIZE = 1000000 - - -def get_size_from_file_stream(file_object): - """ - Return a file size from a file stream given in parameters - """ - current_position = file_object.tell() - file_object.seek(0, 2) - size = file_object.tell() - file_object.seek(current_position) - return size - - -MESSAGES_TYPE = { - "SensorView": SensorView, - "GroundTruth": GroundTruth, - "SensorData": SensorData, -} - - -class OSITrace: - """This class wrap OSI data. It can import and decode OSI scenarios.""" - - def __init__(self, path=None, type_name="SensorView"): - self.scenario_file = None - self.message_offsets = None - self.type_name = type_name - self.timestep_count = 0 - self.retrieved_scenario_size = 0 - self._int_length = len(struct.pack(" 1000000000: - # Throw a warning if trace file is bigger than 1GB - gb_size_input = round(message_length / 1000000000, 2) - gb_size_output = round(3.307692308 * message_length / 1000000000, 2) - warnings.warn( - f"The trace file you are trying to make readable has the size {gb_size_input}GB. This will generate a readable file with the size {gb_size_output}GB. Make sure you have enough disc space and memory to read the file with your text editor.", - ResourceWarning, - ) - - with open(name, "a") as f: - if interval is None and index is None: - for i in self.get_messages(): - f.write(str(i)) - - if interval is not None and index is None: - if ( - type(interval) == tuple - and len(interval) == 2 - and interval[0] < interval[1] - ): - for i in self.get_messages_in_index_range(interval[0], interval[1]): - f.write(str(i)) - else: - raise Exception( - "Argument 'interval' needs to be a tuple of length 2! The first number must be smaller then the second." - ) - - if interval is None and index is not None: - if type(index) == int: - f.write(str(self.get_message_by_index(0))) - else: - raise Exception("Argument 'index' needs to be of type 'int'") - - if interval is not None and index is not None: - raise Exception("Arguments 'index' and 'interval' can not be set both") diff --git a/osi3trace/OSITrace.py b/osi3trace/OSITrace.py new file mode 100644 index 000000000..dd0baa91c --- /dev/null +++ b/osi3trace/OSITrace.py @@ -0,0 +1,131 @@ +""" +Module to handle and manage OSI trace files. +""" +import lzma +import struct + +from osi3.osi_sensorview_pb2 import SensorView +from osi3.osi_groundtruth_pb2 import GroundTruth +from osi3.osi_sensordata_pb2 import SensorData + + +MESSAGES_TYPE = { + "SensorView": SensorView, + "GroundTruth": GroundTruth, + "SensorData": SensorData, +} + + +class OSITrace: + """This class can import and decode OSI trace files.""" + + @staticmethod + def map_message_type(type_name): + """Map the type name to the protobuf message type.""" + return MESSAGES_TYPE[type_name] + + def __init__(self, path=None, type_name="SensorView"): + self.type = self.map_message_type(type_name) + self.file = None + self.message_offsets = None + self.read_complete = False + self.read_limit = None + self._header_length = 4 + if path: + self.from_file(path, type_name) + + def from_file(self, path, type_name="SensorView"): + """Import a trace from a file""" + self.type = self.map_message_type(type_name) + + if path.lower().endswith((".lzma", ".xz")): + self.file = lzma.open(path, "rb") + else: + self.file = open(path, "rb") + + self.read_complete = False + self.read_limit = 0 + self.message_offsets = [0] + + def retrieve_offsets(self, limit=None): + """Retrieve the offsets of the messages from the file.""" + if not self.read_complete: + self.file.seek(self.read_limit, 0) + while not self.read_complete and not limit or len(self.message_offsets) < limit: + self.retrieve_message(skip=True) + return self.message_offsets + + def read_message(self, offset=None, skip=False): + """Read a message from the file at the given offset.""" + if offset: + self.file.seek(offset, 0) + message = self.type() + header = self.file.read(self._header_length) + if len(header) < self._header_length: + return None + message_length = struct.unpack(" len(self.message_offsets): + self.retrieve_offsets(index) + return self.read_message(self.message_offsets[index]) + + def get_messages(self): + return self.get_messages_in_index_range(0, None) + + def get_messages_in_index_range(self, begin, end): + """ + Yield an iterator over messages of indexes between begin and end included. + """ + if begin > len(self.message_offsets): + self.retrieve_offsets(begin) + self.file.seek(self.message_offsets[begin], 0) + current = begin + while end is None or current < end: + message = ( + self.retrieve_message() + if current >= len(self.message_offsets) + else self.read_message() + ) + if message is None: + break + yield message + current += 1 + + def close(self): + if self.file: + self.file.close() + self.file = None + self.message_offsets = None + self.read_complete = False + self.read_limit = None + self.type = None diff --git a/format/osi2read.py b/osi3trace/osi2read.py similarity index 63% rename from format/osi2read.py rename to osi3trace/osi2read.py index 240507177..52b3becd5 100644 --- a/format/osi2read.py +++ b/osi3trace/osi2read.py @@ -5,24 +5,24 @@ python3 osi2read.py -d trace.osi -o myreadableosifile """ -from OSITrace import OSITrace -import struct -import lzma +from osi3trace.OSITrace import OSITrace import argparse -import os +import pathlib def command_line_arguments(): """Define and handle command line interface""" - dir_path = os.path.dirname(os.path.dirname(os.path.realpath(__file__))) - parser = argparse.ArgumentParser( description="Convert a serialized osi trace file to a readable txth output.", - prog="osi2read converter", + prog="osi2read", ) parser.add_argument( - "--data", "-d", help="Path to the file with serialized data.", type=str + "--data", + "-d", + help="Path to the file with serialized data.", + type=str, + required=True, ) parser.add_argument( "--type", @@ -37,7 +37,6 @@ def command_line_arguments(): "--output", "-o", help="Output name of the file.", - default="converted.txth", type=str, required=False, ) @@ -50,16 +49,17 @@ def main(): args = command_line_arguments() # Initialize the OSI trace class - trace = OSITrace() - trace.from_file(path=args.data, type_name=args.type) + trace = OSITrace(args.data, args.type) - args.output = args.output.split(".", 1)[0] + ".txth" + if not args.output: + path = pathlib.Path(args.data).with_suffix(".txth") + args.output = str(path) - if args.output == "converted.txth": - args.output = args.data.split(".", 1)[0] + ".txth" + with open(args.output, "wt") as f: + for message in trace: + f.write(str(message)) - trace.make_readable(args.output) - trace.scenario_file.close() + trace.close() if __name__ == "__main__": diff --git a/pyproject.toml b/pyproject.toml index 17025a2d1..6627fa881 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -30,3 +30,6 @@ dynamic = ["version"] Homepage = "https://github.com/OpenSimulationInterface/open-simulation-interface" Repository = "https://github.com/OpenSimulationInterface/open-simulation-interface.git" "Bug Tracker" = "https://github.com/OpenSimulationInterface/open-simulation-interface/issues" + +[project.scripts] +osi2read = "osi3trace.osi2read:main" diff --git a/setup.py b/setup.py index 06014faaa..5a310a8b3 100644 --- a/setup.py +++ b/setup.py @@ -155,7 +155,7 @@ def run(self): + "." + str(VERSION_PATCH) + (VERSION_SUFFIX or ""), - packages=[package_name], + packages=[package_name, "osi3trace"], cmdclass={ "sdist": CustomSDistCommand, "build_py": CustomBuildPyCommand, From 2a89e615e790df020e5d78db3cc1a880d76fc259 Mon Sep 17 00:00:00 2001 From: "Pierre R. Mai" Date: Thu, 29 Feb 2024 12:31:55 +0100 Subject: [PATCH 060/113] Refactor OSITrace further and add optional caching Also renames the module file to fit PEP-8 conventions. Signed-off-by: Pierre R. Mai --- osi3trace/OSITrace.py | 131 ------------------------------- osi3trace/osi2read.py | 2 +- osi3trace/osi_trace.py | 168 ++++++++++++++++++++++++++++++++++++++++ tests/test_osi_trace.py | 11 +-- 4 files changed, 175 insertions(+), 137 deletions(-) delete mode 100644 osi3trace/OSITrace.py create mode 100644 osi3trace/osi_trace.py diff --git a/osi3trace/OSITrace.py b/osi3trace/OSITrace.py deleted file mode 100644 index dd0baa91c..000000000 --- a/osi3trace/OSITrace.py +++ /dev/null @@ -1,131 +0,0 @@ -""" -Module to handle and manage OSI trace files. -""" -import lzma -import struct - -from osi3.osi_sensorview_pb2 import SensorView -from osi3.osi_groundtruth_pb2 import GroundTruth -from osi3.osi_sensordata_pb2 import SensorData - - -MESSAGES_TYPE = { - "SensorView": SensorView, - "GroundTruth": GroundTruth, - "SensorData": SensorData, -} - - -class OSITrace: - """This class can import and decode OSI trace files.""" - - @staticmethod - def map_message_type(type_name): - """Map the type name to the protobuf message type.""" - return MESSAGES_TYPE[type_name] - - def __init__(self, path=None, type_name="SensorView"): - self.type = self.map_message_type(type_name) - self.file = None - self.message_offsets = None - self.read_complete = False - self.read_limit = None - self._header_length = 4 - if path: - self.from_file(path, type_name) - - def from_file(self, path, type_name="SensorView"): - """Import a trace from a file""" - self.type = self.map_message_type(type_name) - - if path.lower().endswith((".lzma", ".xz")): - self.file = lzma.open(path, "rb") - else: - self.file = open(path, "rb") - - self.read_complete = False - self.read_limit = 0 - self.message_offsets = [0] - - def retrieve_offsets(self, limit=None): - """Retrieve the offsets of the messages from the file.""" - if not self.read_complete: - self.file.seek(self.read_limit, 0) - while not self.read_complete and not limit or len(self.message_offsets) < limit: - self.retrieve_message(skip=True) - return self.message_offsets - - def read_message(self, offset=None, skip=False): - """Read a message from the file at the given offset.""" - if offset: - self.file.seek(offset, 0) - message = self.type() - header = self.file.read(self._header_length) - if len(header) < self._header_length: - return None - message_length = struct.unpack(" len(self.message_offsets): - self.retrieve_offsets(index) - return self.read_message(self.message_offsets[index]) - - def get_messages(self): - return self.get_messages_in_index_range(0, None) - - def get_messages_in_index_range(self, begin, end): - """ - Yield an iterator over messages of indexes between begin and end included. - """ - if begin > len(self.message_offsets): - self.retrieve_offsets(begin) - self.file.seek(self.message_offsets[begin], 0) - current = begin - while end is None or current < end: - message = ( - self.retrieve_message() - if current >= len(self.message_offsets) - else self.read_message() - ) - if message is None: - break - yield message - current += 1 - - def close(self): - if self.file: - self.file.close() - self.file = None - self.message_offsets = None - self.read_complete = False - self.read_limit = None - self.type = None diff --git a/osi3trace/osi2read.py b/osi3trace/osi2read.py index 52b3becd5..c6bee861e 100644 --- a/osi3trace/osi2read.py +++ b/osi3trace/osi2read.py @@ -5,7 +5,7 @@ python3 osi2read.py -d trace.osi -o myreadableosifile """ -from osi3trace.OSITrace import OSITrace +from osi3trace.osi_trace import OSITrace import argparse import pathlib diff --git a/osi3trace/osi_trace.py b/osi3trace/osi_trace.py new file mode 100644 index 000000000..49453c660 --- /dev/null +++ b/osi3trace/osi_trace.py @@ -0,0 +1,168 @@ +""" +Module to handle and manage OSI trace files. +""" +import lzma +import struct + +from osi3.osi_sensorview_pb2 import SensorView +from osi3.osi_groundtruth_pb2 import GroundTruth +from osi3.osi_sensordata_pb2 import SensorData + + +MESSAGES_TYPE = { + "SensorView": SensorView, + "GroundTruth": GroundTruth, + "SensorData": SensorData, +} + + +class OSITrace: + """This class can import and decode OSI trace files.""" + + @staticmethod + def map_message_type(type_name): + """Map the type name to the protobuf message type.""" + return MESSAGES_TYPE[type_name] + + def __init__(self, path=None, type_name="SensorView", cache_messages=False): + self.type = self.map_message_type(type_name) + self.file = None + self.current_index = None + self.message_offsets = None + self.read_complete = False + self.message_cache = {} if cache_messages else None + self._header_length = 4 + if path: + self.from_file(path, type_name, cache_messages) + + def from_file(self, path, type_name="SensorView", cache_messages=False): + """Import a trace from a file""" + self.type = self.map_message_type(type_name) + + if path.lower().endswith((".lzma", ".xz")): + self.file = lzma.open(path, "rb") + else: + self.file = open(path, "rb") + + self.read_complete = False + self.current_index = 0 + self.message_offsets = [0] + self.message_cache = {} if cache_messages else None + + def retrieve_offsets(self, limit=None): + """Retrieve the offsets of the messages from the file.""" + if not self.read_complete: + self.current_index = len(self.message_offsets) - 1 + self.file.seek(self.message_offsets[-1], 0) + while ( + not self.read_complete and not limit or len(self.message_offsets) <= limit + ): + self.retrieve_message(skip=True) + return self.message_offsets + + def retrieve_message(self, index=None, skip=False): + """Retrieve the next message from the file at the current position or given index, or skip it if skip is true.""" + if index is not None: + self.current_index = index + self.file.seek(self.message_offsets[index], 0) + if self.message_cache is not None and self.current_index in self.message_cache: + message = self.message_cache[self.current_index] + self.current_index += 1 + if self.current_index == len(self.message_offsets): + self.file.seek(0, 2) + else: + self.file.seek(self.message_offsets[self.current_index], 0) + if skip: + return self.message_offsets[self.current_index] + else: + return message + start = self.file.tell() + header = self.file.read(self._header_length) + if len(header) < self._header_length: + if start == self.message_offsets[-1]: + self.message_offsets.pop() + self.read_complete = True + self.file.seek(start, 0) + return None + message_length = struct.unpack("= len(self.message_offsets): + self.retrieve_offsets(index) + if self.message_cache is not None and index in self.message_cache: + return self.message_cache[index] + return self.retrieve_message(index=index) + + def get_messages(self): + """ + Yield an iterator over all messages in the file. + """ + return self.get_messages_in_index_range(0, None) + + def get_messages_in_index_range(self, begin, end): + """ + Yield an iterator over messages of indexes between begin and end included. + """ + if begin >= len(self.message_offsets): + self.retrieve_offsets(begin) + self.restart(begin) + current = begin + while end is None or current < end: + if self.message_cache is not None and current in self.message_cache: + yield self.message_cache[current] + else: + message = self.retrieve_message() + if message is None: + break + yield message + current += 1 + + def close(self): + if self.file: + self.file.close() + self.file = None + self.current_index = None + self.message_cache = None + self.message_offsets = None + self.read_complete = False + self.read_limit = None + self.type = None diff --git a/tests/test_osi_trace.py b/tests/test_osi_trace.py index c832b63d7..8a9a430ec 100644 --- a/tests/test_osi_trace.py +++ b/tests/test_osi_trace.py @@ -2,7 +2,7 @@ import tempfile import unittest -from format.OSITrace import OSITrace +from osi3trace.osi_trace import OSITrace from osi3.osi_sensorview_pb2 import SensorView import struct @@ -14,10 +14,11 @@ def test_osi_trace(self): path_input = os.path.join(tmpdirname, "input.osi") create_sample(path_input) - trace = OSITrace() - trace.from_file(path=path_input) - trace.make_readable(path_output, index=1) - trace.scenario_file.close() + trace = OSITrace(path_input) + with open(path_output, "wt") as f: + for message in trace: + f.write(str(message)) + trace.close() self.assertTrue(os.path.exists(path_output)) From 6fc2d4ae84abe032089baf3ce5de82db4911ba51 Mon Sep 17 00:00:00 2001 From: Thomas Sedlmayer Date: Tue, 12 Mar 2024 11:49:00 +0100 Subject: [PATCH 061/113] Remove OpenSCENARIO todo comment Signed-off-by: Thomas Sedlmayer --- osi_object.proto | 2 -- 1 file changed, 2 deletions(-) diff --git a/osi_object.proto b/osi_object.proto index a40873785..db248768f 100644 --- a/osi_object.proto +++ b/osi_object.proto @@ -520,8 +520,6 @@ message MovingObject // * identifier[0] = Entity-Type ("Vehicle" or "Pedestrian") // * identifier[1] = name of Vehicle/Pedestrian in Entity // - // \todo OpenSCENARIO currently does not provide an animal type. - // // \note For non-ASAM Standards, it is implementation-specific how // source_reference is resolved. // From 41ceeef0593a816e411c86ddf66ebb7ef90f1b47 Mon Sep 17 00:00:00 2001 From: Thomas Sedlmayer Date: Wed, 20 Mar 2024 11:14:42 +0100 Subject: [PATCH 062/113] Fix documentation on FeatureData messages - Edit architecture overview concerning FeatureData/top level messages - Remove FeatureData specific adoc - Move contents to sensor_data.adoc Signed-off-by: Thomas Sedlmayer --- doc/architecture/architecture_overview.adoc | 2 +- doc/architecture/feature_data.adoc | 9 --------- doc/architecture/sensor_data.adoc | 4 ++++ doc/open-simulation-interface_user_guide.adoc | 2 -- 4 files changed, 5 insertions(+), 12 deletions(-) delete mode 100644 doc/architecture/feature_data.adoc diff --git a/doc/architecture/architecture_overview.adoc b/doc/architecture/architecture_overview.adoc index 9d8a20228..b82f173aa 100644 --- a/doc/architecture/architecture_overview.adoc +++ b/doc/architecture/architecture_overview.adoc @@ -7,7 +7,7 @@ endif::[] OSI contains an object-based environment description that uses the message format of the https://github.com/protocolbuffers/protobuf/wiki[Protocol Buffer] library. Google developed and maintains the Protocol Buffer library. OSI defines top-level messages that are used to exchange data between separate models. -Top-level messages define the `GroundTruth` interface, the `SensorData` interface, and – since OSI version 3.0.0 – the interfaces `SensorView`, `SensorViewConfiguration`, and `FeatureData`. +Top-level messages define the `GroundTruth` interface, the `SensorData` interface, and – since OSI version 3.0.0 – the interfaces `SensorView` and `SensorViewConfiguration`. Further top-level messages that were added in later versions of OSI are `TrafficCommand`, `TrafficUpdate`, `MotionRequest`, and `StreamingUpdate`. The following figure shows the interfaces and models involved in modeling a sensor. diff --git a/doc/architecture/feature_data.adoc b/doc/architecture/feature_data.adoc deleted file mode 100644 index f6ebf271f..000000000 --- a/doc/architecture/feature_data.adoc +++ /dev/null @@ -1,9 +0,0 @@ -ifndef::include-only-once[] -:root-path: ../ -include::{root-path}_config.adoc[] -endif::[] -= Feature data - -`FeatureData` messages contain detected features in the reference frame of a sensor. -`FeatureData` messages are generated from `GroundTruth` messages. -They serve, for example, as an input to sensor models simulating object detection or feature fusion models. diff --git a/doc/architecture/sensor_data.adoc b/doc/architecture/sensor_data.adoc index f06383960..b44f0eeaa 100644 --- a/doc/architecture/sensor_data.adoc +++ b/doc/architecture/sensor_data.adoc @@ -9,3 +9,7 @@ They can be generated from `GroundTruth` messages, `SensorView` messages, `Featu With the exception of feature data, all information regarding the environment is given with respect to the virtual sensor coordinate system. Feature data is given with respect to the physical sensor coordinate system. Sensor data can be used as input for an automated driving function, a sensor model simulating limited perception, or a sensor fusion model. + +`SensorData` messages include `FeatureData` messages which contain detected features in the reference frame of a sensor. +`FeatureData` messages are generated from `GroundTruth` messages. +They serve, for example, as an input to sensor models simulating object detection or feature fusion models. diff --git a/doc/open-simulation-interface_user_guide.adoc b/doc/open-simulation-interface_user_guide.adoc index b9864441e..f45cc65c2 100644 --- a/doc/open-simulation-interface_user_guide.adoc +++ b/doc/open-simulation-interface_user_guide.adoc @@ -15,8 +15,6 @@ include::./architecture/architecture_overview.adoc[leveloffset=+2] include::./architecture/ground_truth.adoc[leveloffset=+3] -include::./architecture/feature_data.adoc[leveloffset=+3] - include::./architecture/sensor_view.adoc[leveloffset=+3] include::./architecture/sensor_view_configuration.adoc[leveloffset=+3] From f7b5409c29b7887be09ab1fc216c36b01fc26c4d Mon Sep 17 00:00:00 2001 From: "Pierre R. Mai" Date: Mon, 25 Mar 2024 11:48:39 +0100 Subject: [PATCH 063/113] Adjust formatting Signed-off-by: Pierre R. Mai --- doc/architecture/architecture_overview.adoc | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/doc/architecture/architecture_overview.adoc b/doc/architecture/architecture_overview.adoc index b82f173aa..7a9e98828 100644 --- a/doc/architecture/architecture_overview.adoc +++ b/doc/architecture/architecture_overview.adoc @@ -7,7 +7,8 @@ endif::[] OSI contains an object-based environment description that uses the message format of the https://github.com/protocolbuffers/protobuf/wiki[Protocol Buffer] library. Google developed and maintains the Protocol Buffer library. OSI defines top-level messages that are used to exchange data between separate models. -Top-level messages define the `GroundTruth` interface, the `SensorData` interface, and – since OSI version 3.0.0 – the interfaces `SensorView` and `SensorViewConfiguration`. Further top-level messages that were added in later versions of OSI are `TrafficCommand`, `TrafficUpdate`, `MotionRequest`, and `StreamingUpdate`. +Top-level messages define the `GroundTruth` interface, the `SensorData` interface, and – since OSI version 3.0.0 – the interfaces `SensorView` and `SensorViewConfiguration`. +Further top-level messages that were added in later versions of OSI are `TrafficCommand`, `TrafficUpdate`, `MotionRequest`, and `StreamingUpdate`. The following figure shows the interfaces and models involved in modeling a sensor. From e9cb77205c69ac7966914c1c78c9c73a2f16d80b Mon Sep 17 00:00:00 2001 From: Thomas Sedlmayer Date: Fri, 22 Mar 2024 10:00:18 +0100 Subject: [PATCH 064/113] Add proj frame offset to groundtruth Signed-off-by: Thomas Sedlmayer --- osi_groundtruth.proto | 44 ++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 43 insertions(+), 1 deletion(-) diff --git a/osi_groundtruth.proto b/osi_groundtruth.proto index 651ff7e81..d883db4bb 100644 --- a/osi_groundtruth.proto +++ b/osi_groundtruth.proto @@ -133,7 +133,8 @@ message GroundTruth optional uint32 country_code = 13; // Projection string that allows to transform all coordinates in GroundTruth - // into a different cartographic projection. + // into a different cartographic projection after the \c proj_frame_offset + // has been applied. // // The string follows the PROJ rules for projections [1]. // @@ -178,4 +179,45 @@ message GroundTruth // Logical lanes used e.g. by traffic agents // repeated LogicalLane logical_lane = 19; + + // Coordinate frame offset to be used for PROJ transformations. + // + optional ProjFrameOffset proj_frame_offset = 20; + + // + // \brief Coordinate frame offset to transform from OSI's global coordinate + // system to a coordinate reference system to be used for given PROJ + // transformations. + // + // If an offset is defined, always apply the \c proj_frame_offset on + // global OSI coordinates before applying any transformations defined in + // \c proj_string. + // + // To apply the offset, global coordinates are first translated by the given + // positional offset (x,y,z). Then, the yaw angle is used to rotate around + // the new origin. + // + // The offset is applied on global OSI coordinates using an affine + // transformation with rotation around z-axis: + // xWorld = xOSI * cos(yaw) - yOSI * sin(yaw) + xOffset + // yWorld = xOSI * sin(yaw) + yOSI * cos(yaw) + yOffset + // zWorld = zOSI + zOffset + // + // If no yaw is provided (recommended), the formulas simplify to: + // xWorld = xOSI + xOffset + // yWorld = yOSI + yOffset + // zWorld = zOSI + zOffset + // + message ProjFrameOffset + { + // Positional offset for relocation of the coordinate frame. + // + optional Vector3d position = 1; + + // Yaw/heading angle for re-orientation of the coordinate frame around + // the z-axis. + // + optional double yaw = 2; + } + } From 4930e3b90be30e50d5929ecd22c9f1d14b67c102 Mon Sep 17 00:00:00 2001 From: Thomas Sedlmayer Date: Fri, 22 Mar 2024 10:14:55 +0100 Subject: [PATCH 065/113] Add spelling exceptions Signed-off-by: Thomas Sedlmayer --- .github/spelling_custom_words_en_US.txt | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.github/spelling_custom_words_en_US.txt b/.github/spelling_custom_words_en_US.txt index a88e44be9..592d59468 100644 --- a/.github/spelling_custom_words_en_US.txt +++ b/.github/spelling_custom_words_en_US.txt @@ -2,6 +2,7 @@ abc absteigen adas ADR +affine agbl al Allgemeine @@ -244,6 +245,7 @@ openscenario optischen Ordnung osi +OSI's osmp Ouml ouml From a604f5a05fd7820a81e38aadb9618af8c0f7417d Mon Sep 17 00:00:00 2001 From: Thomas Sedlmayer Date: Fri, 22 Mar 2024 10:25:34 +0100 Subject: [PATCH 066/113] Add empty lines for better formatting in doxygen Signed-off-by: Thomas Sedlmayer --- osi_groundtruth.proto | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/osi_groundtruth.proto b/osi_groundtruth.proto index d883db4bb..ddcb25e96 100644 --- a/osi_groundtruth.proto +++ b/osi_groundtruth.proto @@ -199,13 +199,20 @@ message GroundTruth // // The offset is applied on global OSI coordinates using an affine // transformation with rotation around z-axis: + // // xWorld = xOSI * cos(yaw) - yOSI * sin(yaw) + xOffset + // // yWorld = xOSI * sin(yaw) + yOSI * cos(yaw) + yOffset + // // zWorld = zOSI + zOffset // + // // If no yaw is provided (recommended), the formulas simplify to: + // // xWorld = xOSI + xOffset + // // yWorld = yOSI + yOffset + // // zWorld = zOSI + zOffset // message ProjFrameOffset From 66218d756b3aadb97270bbfefe42f57edf40c069 Mon Sep 17 00:00:00 2001 From: Thomas Sedlmayer Date: Fri, 22 Mar 2024 13:52:12 +0100 Subject: [PATCH 067/113] Add proj frame offset explanations to documentation Signed-off-by: Thomas Sedlmayer --- doc/architecture/reference_points_coordinate_systems.adoc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/architecture/reference_points_coordinate_systems.adoc b/doc/architecture/reference_points_coordinate_systems.adoc index 4c6ea7343..c2eb3fe95 100644 --- a/doc/architecture/reference_points_coordinate_systems.adoc +++ b/doc/architecture/reference_points_coordinate_systems.adoc @@ -12,7 +12,7 @@ Coordinate system for all entities that are part of ground truth. The global coordinate system is an inertial x/y/z-coordinate system. The origin is the global reference point that is determined by the environment simulation. This reference point may be derived from map data or other considerations. -Global coordinates can be mapped to a geographic coordinate system via `osi3::GroundTruth::proj_string`. +Global coordinates can be mapped to a geographic coordinate system via `osi3::GroundTruth::proj_string`. Note that before applying any PROJ transformations to global coordinates, the `osi3::GroundTruth::proj_frame_offset` must be applied. Host vehicle coordinate system:: The host vehicle coordinate system's origin is defined to be at the center of the rear axle of the host vehicle. From 274859c9f6c62a7665907987567945806d8136f3 Mon Sep 17 00:00:00 2001 From: "Pierre R. Mai" Date: Fri, 22 Mar 2024 16:49:10 +0100 Subject: [PATCH 068/113] Formatting fix Signed-off-by: Pierre R. Mai --- doc/architecture/reference_points_coordinate_systems.adoc | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/doc/architecture/reference_points_coordinate_systems.adoc b/doc/architecture/reference_points_coordinate_systems.adoc index c2eb3fe95..b32eb8392 100644 --- a/doc/architecture/reference_points_coordinate_systems.adoc +++ b/doc/architecture/reference_points_coordinate_systems.adoc @@ -12,7 +12,8 @@ Coordinate system for all entities that are part of ground truth. The global coordinate system is an inertial x/y/z-coordinate system. The origin is the global reference point that is determined by the environment simulation. This reference point may be derived from map data or other considerations. -Global coordinates can be mapped to a geographic coordinate system via `osi3::GroundTruth::proj_string`. Note that before applying any PROJ transformations to global coordinates, the `osi3::GroundTruth::proj_frame_offset` must be applied. +Global coordinates can be mapped to a geographic coordinate system via `osi3::GroundTruth::proj_string`. +Note that before applying any PROJ transformations to global coordinates, the `osi3::GroundTruth::proj_frame_offset` must be applied. Host vehicle coordinate system:: The host vehicle coordinate system's origin is defined to be at the center of the rear axle of the host vehicle. From 38ee7da5a978baa88475bee569c80417e9582098 Mon Sep 17 00:00:00 2001 From: Thomas Sedlmayer Date: Fri, 15 Mar 2024 09:20:46 +0100 Subject: [PATCH 069/113] Add system time to sensor data Signed-off-by: Thomas Sedlmayer --- osi_sensordata.proto | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/osi_sensordata.proto b/osi_sensordata.proto index 18df69230..5ac1dc8d8 100644 --- a/osi_sensordata.proto +++ b/osi_sensordata.proto @@ -336,4 +336,11 @@ message SensorData // Virtual detection area of the sensor // optional VirtualDetectionArea virtual_detection_area = 28; + + // The system time of the sensor data, given in UTC (Unix Epoch timestamp). + // + // The system time can be used to set the corresponding component's internal + // time which may not coincide with the simulation time frame. + // + optional Timestamp system_time = 29; } From c050a9381574a5ba24907b0f2d8bcc5ced6c6104 Mon Sep 17 00:00:00 2001 From: "Pierre R. Mai" Date: Fri, 22 Mar 2024 16:42:16 +0100 Subject: [PATCH 070/113] Enhance desription of system_time field Signed-off-by: Pierre R. Mai --- osi_sensordata.proto | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/osi_sensordata.proto b/osi_sensordata.proto index 5ac1dc8d8..9ece68316 100644 --- a/osi_sensordata.proto +++ b/osi_sensordata.proto @@ -337,10 +337,14 @@ message SensorData // optional VirtualDetectionArea virtual_detection_area = 28; - // The system time of the sensor data, given in UTC (Unix Epoch timestamp). - // - // The system time can be used to set the corresponding component's internal - // time which may not coincide with the simulation time frame. + // The system time of the modeled source of the sensor data, given + // in UTC (Unix Epoch timestamp). + // + // The system time can be used to transmit the internal time of the + // simulated component that supplies the sensor data, which might + // not coincide with the simulation time as transmitted in the + // timestamp field. Example use cases include recorded data traces + // or the simulation of time synchronization mechanisms and errors. // optional Timestamp system_time = 29; } From 560469c9f9ec766c98eabb3d011451760059469c Mon Sep 17 00:00:00 2001 From: Thomas Sedlmayer Date: Fri, 22 Mar 2024 12:24:53 +0100 Subject: [PATCH 071/113] Add pyspelling html filter Signed-off-by: Thomas Sedlmayer --- .github/.pyspelling.yml | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/.github/.pyspelling.yml b/.github/.pyspelling.yml index 5670d5b6e..512d9a26d 100644 --- a/.github/.pyspelling.yml +++ b/.github/.pyspelling.yml @@ -17,3 +17,8 @@ matrix: delimiters: - open: '(?s)^(?P *\/\/)' close: '^(?P=open)$' + - pyspelling.filters.html: + comments: true + attributes: + - title + - alt From 213f4de4fc4b67b93de0262e8fd6005a2710fbb6 Mon Sep 17 00:00:00 2001 From: Thomas Sedlmayer Date: Mon, 25 Mar 2024 14:28:57 +0100 Subject: [PATCH 072/113] Update spellchecker whitelist Signed-off-by: Thomas Sedlmayer --- .github/spelling_custom_words_en_US.txt | 22 ++++++++++++++++++++-- 1 file changed, 20 insertions(+), 2 deletions(-) diff --git a/.github/spelling_custom_words_en_US.txt b/.github/spelling_custom_words_en_US.txt index 592d59468..af03471c5 100644 --- a/.github/spelling_custom_words_en_US.txt +++ b/.github/spelling_custom_words_en_US.txt @@ -20,6 +20,7 @@ auch auf auml Ausfahrt +außer Baugebiet Baustelle Baustellen @@ -89,6 +90,7 @@ dt Duesseldorf Durchgangsverkehr dvr +dürfen easting EBIKES edn @@ -127,6 +129,8 @@ Fak fcm fehlende Feiertagen +Flächen +flächen fmu Formelsammlung Formelzeichen @@ -138,6 +142,7 @@ fuer fullreports ge geb +gebührenpflichtig Gedeon Gefahrenzeichen gekennzeichneten @@ -145,6 +150,7 @@ gekennzeichneter Gelegenheitsverkehr Geospatial gesetze +geändert github glichkeit GNSS @@ -152,6 +158,7 @@ grayscale gridded Groessen GroundTruthInit +Grüne gulleys haben Hafengebiet @@ -208,6 +215,7 @@ lte luminance luv lx +Lärmschutz Mainz Meteorologische metoffice @@ -239,8 +247,8 @@ oktas ONEWAY onlinepubs ONRAMP -opengroup opendrive +opengroup openscenario optischen Ordnung @@ -254,8 +262,10 @@ parametrize Parkausweis Parken Parkfl +Parkflächen Parkschein Parkst +Parkstände Paulat pdf png @@ -281,6 +291,7 @@ rcs rdquo README Rei +Reißverschluss rfc rfen rgb @@ -291,6 +302,7 @@ rmschutz rmse Rollsplitt Rosenberger +räumen Sa SAE sae @@ -319,6 +331,7 @@ Strahlungsphysik Strassenfahrzeuge Strassenverkehrs strassenverkehrsordnung +Straßenschaden StVO stvo StVZO @@ -357,6 +370,7 @@ vda verkehr Verkehrseinrichtungen Verkehrsf +Verkehrsführung Verkehrstechnik verkehrszeichen verschluss @@ -365,12 +379,13 @@ Vorfahrt Vorschriftzeichen Vorweg vz -vzkat VzKat +vzkat wa Welle Wellenausbreitung Wendem +Wendemöglichkeit werden werktags Wernli @@ -382,6 +397,7 @@ wp wsdot www www +während xrat XXXX xy @@ -391,3 +407,5 @@ Zeitschrift Zou Zufahrt Zuflussregelung +Ölspur +überholt From 66abe1275772dbcce8aa3c5fa3eee0cf6e2e2a46 Mon Sep 17 00:00:00 2001 From: Thomas Sedlmayer Date: Tue, 26 Mar 2024 08:55:37 +0100 Subject: [PATCH 073/113] Remove partial words from spellchecker whitelist Signed-off-by: Thomas Sedlmayer --- .github/spelling_custom_words_en_US.txt | 21 --------------------- 1 file changed, 21 deletions(-) diff --git a/.github/spelling_custom_words_en_US.txt b/.github/spelling_custom_words_en_US.txt index af03471c5..ee6e0358f 100644 --- a/.github/spelling_custom_words_en_US.txt +++ b/.github/spelling_custom_words_en_US.txt @@ -15,7 +15,6 @@ antecessor arg asam atsc -au auch auf auml @@ -34,7 +33,6 @@ bei beleuchtung Benrath Bereich -berholt Besondere Bewohner BGBl @@ -56,7 +54,6 @@ cd cellpadding cellspacing centerline -chen Cianciaruso CIE cie @@ -109,7 +106,6 @@ Endeninch endlink endrules engl -enschaden enum enums eoas @@ -152,7 +148,6 @@ Geospatial gesetze geändert github -glichkeit GNSS grayscale gridded @@ -167,9 +162,6 @@ halten hier Hochwasser href -hrend -hrenpflichtig -hrung hsv htm html @@ -210,7 +202,6 @@ lidar lidar's Linksabbieger lm -lspur lte luminance luv @@ -225,8 +216,6 @@ Modellierung MULTITRACK nd nde -ndert -ne NEBEL Nebenstrecke neuer @@ -261,10 +250,8 @@ parametrization parametrize Parkausweis Parken -Parkfl Parkflächen Parkschein -Parkst Parkstände Paulat pdf @@ -290,15 +277,12 @@ rbd rcs rdquo README -Rei Reißverschluss rfc -rfen rgb rgbir rggb Richtzeichen -rmschutz rmse Rollsplitt Rosenberger @@ -326,7 +310,6 @@ sr sslnet Steinburg steradian -Stra Strahlungsphysik Strassenfahrzeuge Strassenverkehrs @@ -356,7 +339,6 @@ ubc ubc uint uk -umen umich umtri und @@ -373,7 +355,6 @@ Verkehrsf Verkehrsführung Verkehrstechnik verkehrszeichen -verschluss Verschmutzte Vorfahrt Vorschriftzeichen @@ -384,7 +365,6 @@ vzkat wa Welle Wellenausbreitung -Wendem Wendemöglichkeit werden werktags @@ -396,7 +376,6 @@ Wilster wp wsdot www -www während xrat XXXX From 6c20ed43e9a4f22b0315b2b0d84f2b56802add86 Mon Sep 17 00:00:00 2001 From: "Pierre R. Mai" Date: Fri, 8 Mar 2024 11:31:09 +0100 Subject: [PATCH 074/113] Deprecate various car types in favor of new alias TYPE_CAR This is a result of the harmonization effort across ASAM Open standards Signed-off-by: Pierre R. Mai --- osi_object.proto | 29 +++++++++++++++++++++++++---- 1 file changed, 25 insertions(+), 4 deletions(-) diff --git a/osi_object.proto b/osi_object.proto index db248768f..8e1d8a1a1 100644 --- a/osi_object.proto +++ b/osi_object.proto @@ -764,10 +764,12 @@ message MovingObject // other OpenX standards (in particular, OpenScenario 1.x and 2.x, and OpenLabel). // This is primarily for historical reasons. Where a single type from a // different standard can map to multiple OSI types it is left up to the - // discretion of the OSI implementer how that mapping is achieved. For example, - // a simulator may use the dimensions of a provided 3d model of a vehicle with type - // "car" in OpenScenario, to determine whether it should be a TYPE_SMALL_CAR or - // TYPE_MEDIUM_CAR in OSI. + // discretion of the OSI implementer how that mapping is achieved. In previous + // versions, for example, a simulator might have used the dimensions of a provided + // 3d model of a vehicle with type "car" in OpenScenario, to determine whether it + // should be a TYPE_SMALL_CAR or TYPE_MEDIUM_CAR in OSI. As part of the harmonization + // effort, it should now map to TYPE_CAR, which is an alias of the old TYPE_MEDIUM_CAR, + // and all other car type enums have been deprecated in favor of TYPE_CAR. // // \note Vehicle type classification is a complex area and there are no // universally recognized standards. As such, the boundaries between some of the @@ -778,6 +780,10 @@ message MovingObject // enum Type { + // Allow aliases in enum + // + option allow_alias = true; + // Type of vehicle is unknown (must not be used in ground truth). // TYPE_UNKNOWN = 0; @@ -790,24 +796,39 @@ message MovingObject // // Definition: Hatchback car with maximum length 4 m. // + // \note Deprecated differentiation, use TYPE_CAR instead + // TYPE_SMALL_CAR = 2; // Vehicle is a compact car. // // Definition: Hatchback car with length between 4 and 4.5 m. // + // \note Deprecated differentiation, use TYPE_CAR instead + // TYPE_COMPACT_CAR = 3; + // Vehicle is a car. + // + // This is to be used for all car-like vehicles, without any + // further differentiated type available. + // + TYPE_CAR = 4; + // Vehicle is a medium car. // // Definition: Hatchback or sedan with length between 4.5 and 5 m. // + // \note Deprecated differentiation, use TYPE_CAR instead, which is an alias + // TYPE_MEDIUM_CAR = 4; // Vehicle is a luxury car. // // Definition: Sedan or coupe that is longer then 5 m. // + // \note Deprecated differentiation, use TYPE_CAR instead + // TYPE_LUXURY_CAR = 5; // Vehicle is a delivery van. From 7b38bedad805448f5e78245ef89ae91efd6ee051 Mon Sep 17 00:00:00 2001 From: "Pierre R. Mai" Date: Fri, 22 Mar 2024 16:50:11 +0100 Subject: [PATCH 075/113] Review feedback rewording Co-authored-by: jakobkaths <54845080+jakobkaths@users.noreply.github.com> Signed-off-by: Pierre R. Mai --- osi_object.proto | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osi_object.proto b/osi_object.proto index 8e1d8a1a1..fb0c518b3 100644 --- a/osi_object.proto +++ b/osi_object.proto @@ -819,7 +819,7 @@ message MovingObject // // Definition: Hatchback or sedan with length between 4.5 and 5 m. // - // \note Deprecated differentiation, use TYPE_CAR instead, which is an alias + // \note Deprecated differentiation, use the alias TYPE_CAR instead // TYPE_MEDIUM_CAR = 4; From 427d7a6a72c80052e55b7763fe2fa4b8c4644fd7 Mon Sep 17 00:00:00 2001 From: Thomas Sedlmayer Date: Wed, 24 Jan 2024 09:49:46 +0100 Subject: [PATCH 076/113] Rename streaming update image to lowercase Signed-off-by: Thomas Sedlmayer --- ...ng-principle.PNG => osi-streaming-principle.png} | Bin 1 file changed, 0 insertions(+), 0 deletions(-) rename doc/images/{osi-streaming-principle.PNG => osi-streaming-principle.png} (100%) diff --git a/doc/images/osi-streaming-principle.PNG b/doc/images/osi-streaming-principle.png similarity index 100% rename from doc/images/osi-streaming-principle.PNG rename to doc/images/osi-streaming-principle.png From b9d108b1176d2fce1c33fb25d62fc560ae5adf23 Mon Sep 17 00:00:00 2001 From: Markus Lemmer Date: Fri, 22 Dec 2023 10:14:47 +0100 Subject: [PATCH 077/113] Added draft for traffic rule and speed limit. Signed-off-by: Markus Lemmer --- osi_logicallane.proto | 117 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 117 insertions(+) diff --git a/osi_logicallane.proto b/osi_logicallane.proto index e55437011..8bea2a9c5 100644 --- a/osi_logicallane.proto +++ b/osi_logicallane.proto @@ -3,6 +3,7 @@ syntax = "proto2"; option optimize_for = SPEED; import "osi_common.proto"; +import "osi_object.proto"; package osi3; @@ -587,6 +588,10 @@ message LogicalLane // optional string street_name = 16; + // A list of traffic rules on the lane. + // + repeated TrafficRule traffic_rule = 17; + // // Definition of available lane types. // @@ -822,5 +827,117 @@ message LogicalLane // optional double end_s_other = 5; } + + // + // Describes traffic rules on a lane. + // The traffic rule can thereby induced by regulations, traffic signs + // or by other means. If the modeled traffic rule is induced by a traffic sign + // the information should be identical with the respective traffic sign. + // + // Note: Every instance should be corresponding to only one specific rule. + // The type of the traffic rule should be set using the respective filed. + // Additionally, every message should contain the traffic rule validity information + // and the respective field for the respective traffic rule type. + // + // Note: Each traffic rule corresponds to only one lane. If the traffic rule + // is also valid on adjacent/successing/predecessing lanes it needs to be + // specified for each lane individually. + // + // \brief Logical Model of a traffic rule on a lane. + // + message TrafficRule { + + // The type of the traffic rule. + // + // This specifies the type of the traffic rule to be modeled. + // Based on the type the respective message containing the information + // corresponding to the traffic rule should be filled. + // + optional TrafficRuleType traffic_rule_type = 1; + + // The validity information of the traffic rule. + // + optional TrafficRuleValidity traffic_rule_validity = 2; + + // Traffic rule information for traffic rule of type speed limit. + // + optional SpeedLimit speed_limit = 3; + + // + // The type of the the traffic rule. + // + enum TrafficRuleType { + + // Traffic rule is of type speed limit + // + TRAFFIC_RULE_TYPE_SPEED_LIMIT = 0; + } + + // + // \brief Validity information for a traffic rule. + // + message TrafficRuleValidity { + + // + // The starting point of the traffic rule validity on the lane. + // Must be in range [\c sStart,\c sEnd] of the reference line. + // + optional double start_s = 1; + + // + // The ending point of the traffic rule validity on the lane. + // Must be in range [\c sStart,\c sEnd] of the reference line. + // Note: Should always be greater than the starting point. + // + optional double end_s = 2; + + // + // List of vehicle types for which the speed limit is valid. + // If the traffic rule validity is independent of the vehicle type + // the list should be empty. + // + repeated MovingObject.VehicleClassification.Type valid_for_type = 3; + } + + // + // \brief Speed limit on a lane. + // + message SpeedLimit { + + // + // The speed limit in the unit specified by the respective files + // + optional double speed_limit = 1; + + // + // The unit in which the speed limit is specified. + // + optional Unit speed_limit_unit = 2; + + // Unit of the specified speed limit. + // + enum Unit + { + // Meters per second. + // + // Unit: km/h + // + UNIT_METER_PER_SECOND = 1; + + // Kilometers per hour. + // + // Unit: km/h + // + UNIT_KILOMETER_PER_HOUR = 2; + + // Miles per hour. + // + // Unit: mph + // + UNIT_MILE_PER_HOUR = 3; + } + } + } + } From be43ed87471b24585c373ad40044192e63270529 Mon Sep 17 00:00:00 2001 From: Markus Lemmer Date: Fri, 2 Feb 2024 14:14:53 +0100 Subject: [PATCH 078/113] Fixed enumerations. Signed-off-by: Markus Lemmer --- osi_logicallane.proto | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/osi_logicallane.proto b/osi_logicallane.proto index 8bea2a9c5..968e5db5f 100644 --- a/osi_logicallane.proto +++ b/osi_logicallane.proto @@ -870,7 +870,7 @@ message LogicalLane // Traffic rule is of type speed limit // - TRAFFIC_RULE_TYPE_SPEED_LIMIT = 0; + TRAFFIC_RULE_TYPE_SPEED_LIMIT = 1; } // @@ -920,7 +920,7 @@ message LogicalLane { // Meters per second. // - // Unit: km/h + // Unit: m/s // UNIT_METER_PER_SECOND = 1; From 6dfc814f057ef4297f35f43ff7a0019356af1613 Mon Sep 17 00:00:00 2001 From: Markus Lemmer Date: Fri, 2 Feb 2024 14:25:58 +0100 Subject: [PATCH 079/113] Improved documentation. Signed-off-by: Markus Lemmer --- osi_logicallane.proto | 3 +++ 1 file changed, 3 insertions(+) diff --git a/osi_logicallane.proto b/osi_logicallane.proto index 968e5db5f..be21ad5e1 100644 --- a/osi_logicallane.proto +++ b/osi_logicallane.proto @@ -838,6 +838,9 @@ message LogicalLane // The type of the traffic rule should be set using the respective filed. // Additionally, every message should contain the traffic rule validity information // and the respective field for the respective traffic rule type. + // In case of traffic rule (priority) conflicts for rules of the same type that + // can not be depicted using the traffic rule validity only the currently + // valid rule should be provided. // // Note: Each traffic rule corresponds to only one lane. If the traffic rule // is also valid on adjacent/successing/predecessing lanes it needs to be From b9535300b45990ab218492d63a8916da8319d69e Mon Sep 17 00:00:00 2001 From: Markus Lemmer Date: Tue, 6 Feb 2024 09:01:47 +0100 Subject: [PATCH 080/113] Changes enums to start with 0. Signed-off-by: Markus Lemmer --- osi_logicallane.proto | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/osi_logicallane.proto b/osi_logicallane.proto index be21ad5e1..30bee06d6 100644 --- a/osi_logicallane.proto +++ b/osi_logicallane.proto @@ -873,7 +873,7 @@ message LogicalLane // Traffic rule is of type speed limit // - TRAFFIC_RULE_TYPE_SPEED_LIMIT = 1; + TRAFFIC_RULE_TYPE_SPEED_LIMIT = 0; } // @@ -925,19 +925,19 @@ message LogicalLane // // Unit: m/s // - UNIT_METER_PER_SECOND = 1; + UNIT_METER_PER_SECOND = 0; // Kilometers per hour. // // Unit: km/h // - UNIT_KILOMETER_PER_HOUR = 2; + UNIT_KILOMETER_PER_HOUR = 1; // Miles per hour. // // Unit: mph // - UNIT_MILE_PER_HOUR = 3; + UNIT_MILE_PER_HOUR = 2; } } } From c3f987fb8d3970d92608e3456bc244707cfa91f7 Mon Sep 17 00:00:00 2001 From: Markus Lemmer Date: Thu, 22 Feb 2024 09:18:31 +0100 Subject: [PATCH 081/113] Fixed typos. Signed-off-by: Markus Lemmer --- osi_logicallane.proto | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/osi_logicallane.proto b/osi_logicallane.proto index 30bee06d6..ad219dfa0 100644 --- a/osi_logicallane.proto +++ b/osi_logicallane.proto @@ -830,12 +830,12 @@ message LogicalLane // // Describes traffic rules on a lane. - // The traffic rule can thereby induced by regulations, traffic signs + // The traffic rule can thereby be induced by regulations, traffic signs // or by other means. If the modeled traffic rule is induced by a traffic sign // the information should be identical with the respective traffic sign. // // Note: Every instance should be corresponding to only one specific rule. - // The type of the traffic rule should be set using the respective filed. + // The type of the traffic rule should be set using the respective field. // Additionally, every message should contain the traffic rule validity information // and the respective field for the respective traffic rule type. // In case of traffic rule (priority) conflicts for rules of the same type that From 2c7ce0ea9e1d42088675f96157d11fcd21a370bd Mon Sep 17 00:00:00 2001 From: Markus Lemmer Date: Wed, 13 Mar 2024 17:33:00 +0100 Subject: [PATCH 082/113] Modified type and speed limit value as discussed in CCB meeting. Signed-off-by: Markus Lemmer --- osi_logicallane.proto | 61 +++++++++++++++++++++++-------------------- 1 file changed, 32 insertions(+), 29 deletions(-) diff --git a/osi_logicallane.proto b/osi_logicallane.proto index ad219dfa0..cb41e57e4 100644 --- a/osi_logicallane.proto +++ b/osi_logicallane.proto @@ -4,6 +4,7 @@ option optimize_for = SPEED; import "osi_common.proto"; import "osi_object.proto"; +import "osi_trafficsign.proto"; package osi3; @@ -895,51 +896,53 @@ message LogicalLane optional double end_s = 2; // - // List of vehicle types for which the speed limit is valid. + // List of traffic participan types for which the speed limit is valid. // If the traffic rule validity is independent of the vehicle type // the list should be empty. // - repeated MovingObject.VehicleClassification.Type valid_for_type = 3; - } - - // - // \brief Speed limit on a lane. - // - message SpeedLimit { + repeated TypeValidity valid_for_type = 3; // - // The speed limit in the unit specified by the respective files + // \brief Type of traffic paricipant for which a rule is valid. // - optional double speed_limit = 1; + message TypeValidity { - // - // The unit in which the speed limit is specified. - // - optional Unit speed_limit_unit = 2; - - // Unit of the specified speed limit. - // - enum Unit - { - // Meters per second. // - // Unit: m/s + // The type of objects for which the traffic rule applys. + // Must not be UNKNOWN or OTHER // - UNIT_METER_PER_SECOND = 0; - - // Kilometers per hour. + optional MovingObject.Type type = 1; + // - // Unit: km/h + // Vehicle classification type for trafic participants + // May only be set if type is TYPE_VEHICLE. Must not be UNKNOWN or OTHER. // - UNIT_KILOMETER_PER_HOUR = 1; + optional MovingObject.VehicleClassification.Type vehicle_type = 2; - // Miles per hour. // - // Unit: mph + // Role of traffic participant. + // May only be set if type is TYPE_VEHICLE. Must not be UNKNOWN or OTHER. // - UNIT_MILE_PER_HOUR = 2; + optional MovingObject.VehicleClassification.Role vehicle_role = 3; } } + + // + // \brief Speed limit on a lane. + // + message SpeedLimit { + + // + // The value of the speed limit. + // The unit filed in the TrafficSigneValue message may only be set to + // units associated with velocities and must not be UNKNOWN or OTHER. + // + // Note: All speed limits are to be modelled this way, indpendent + // of how they are induced. + // + optional TrafficSignValue speed_limit_value = 1; + + } } } From c9e4b46a0517b425df5d1b76f0f43a44eb69ea32 Mon Sep 17 00:00:00 2001 From: Markus Lemmer Date: Thu, 14 Mar 2024 08:21:15 +0100 Subject: [PATCH 083/113] Fixed spelling issues. Signed-off-by: Markus Lemmer --- osi_logicallane.proto | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/osi_logicallane.proto b/osi_logicallane.proto index cb41e57e4..87e3bd942 100644 --- a/osi_logicallane.proto +++ b/osi_logicallane.proto @@ -844,7 +844,7 @@ message LogicalLane // valid rule should be provided. // // Note: Each traffic rule corresponds to only one lane. If the traffic rule - // is also valid on adjacent/successing/predecessing lanes it needs to be + // is also valid on adjacent/successor/predecessor lanes it needs to be // specified for each lane individually. // // \brief Logical Model of a traffic rule on a lane. @@ -896,25 +896,25 @@ message LogicalLane optional double end_s = 2; // - // List of traffic participan types for which the speed limit is valid. + // List of traffic participant types for which the speed limit is valid. // If the traffic rule validity is independent of the vehicle type // the list should be empty. // repeated TypeValidity valid_for_type = 3; // - // \brief Type of traffic paricipant for which a rule is valid. + // \brief Type of traffic participant for which a rule is valid. // message TypeValidity { // - // The type of objects for which the traffic rule applys. + // The type of object for which the traffic rule is valid. // Must not be UNKNOWN or OTHER // optional MovingObject.Type type = 1; // - // Vehicle classification type for trafic participants + // Vehicle classification type for traffic participants // May only be set if type is TYPE_VEHICLE. Must not be UNKNOWN or OTHER. // optional MovingObject.VehicleClassification.Type vehicle_type = 2; @@ -934,10 +934,10 @@ message LogicalLane // // The value of the speed limit. - // The unit filed in the TrafficSigneValue message may only be set to + // The unit filed in the TrafficSignValue message may only be set to // units associated with velocities and must not be UNKNOWN or OTHER. // - // Note: All speed limits are to be modelled this way, indpendent + // Note: All speed limits are to be led this way, independent // of how they are induced. // optional TrafficSignValue speed_limit_value = 1; From 2b2122bbac5d5dc5894d3023f46cffd4ca4d3143 Mon Sep 17 00:00:00 2001 From: Markus Lemmer Date: Mon, 25 Mar 2024 09:57:19 +0100 Subject: [PATCH 084/113] Fixed spelling issues. Signed-off-by: Markus Lemmer --- osi_logicallane.proto | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osi_logicallane.proto b/osi_logicallane.proto index 87e3bd942..aa06f4f0c 100644 --- a/osi_logicallane.proto +++ b/osi_logicallane.proto @@ -934,7 +934,7 @@ message LogicalLane // // The value of the speed limit. - // The unit filed in the TrafficSignValue message may only be set to + // The unit field in the TrafficSignValue message may only be set to // units associated with velocities and must not be UNKNOWN or OTHER. // // Note: All speed limits are to be led this way, independent From 939daa6a7830d1e44a0cc379f7c1f84d1227566e Mon Sep 17 00:00:00 2001 From: Markus Lemmer Date: Mon, 25 Mar 2024 11:06:30 +0100 Subject: [PATCH 085/113] Adjusted documentation for type validty. Signed-off-by: Markus Lemmer --- osi_logicallane.proto | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/osi_logicallane.proto b/osi_logicallane.proto index aa06f4f0c..3bdee257e 100644 --- a/osi_logicallane.proto +++ b/osi_logicallane.proto @@ -909,19 +909,20 @@ message LogicalLane // // The type of object for which the traffic rule is valid. - // Must not be UNKNOWN or OTHER // optional MovingObject.Type type = 1; // // Vehicle classification type for traffic participants - // May only be set if type is TYPE_VEHICLE. Must not be UNKNOWN or OTHER. + // Should be set to UNKNOWN if type is not TYPE_VEHICLE or the rule + // is valid for all vehicle types. // optional MovingObject.VehicleClassification.Type vehicle_type = 2; // // Role of traffic participant. - // May only be set if type is TYPE_VEHICLE. Must not be UNKNOWN or OTHER. + // Should be set to UNKNOWN if type is not TYPE_VEHICLE or the rule + // is valid for all vehicle roles. // optional MovingObject.VehicleClassification.Role vehicle_role = 3; } @@ -935,9 +936,9 @@ message LogicalLane // // The value of the speed limit. // The unit field in the TrafficSignValue message may only be set to - // units associated with velocities and must not be UNKNOWN or OTHER. + // units associated with velocities and must not be UNKNOWN. // - // Note: All speed limits are to be led this way, independent + // Note: All speed limits are to be modeled this way, independent // of how they are induced. // optional TrafficSignValue speed_limit_value = 1; From e41415ea83b8c731bef59aac11c8e761261f4549 Mon Sep 17 00:00:00 2001 From: "Pierre R. Mai" Date: Thu, 4 Apr 2024 12:08:11 +0200 Subject: [PATCH 086/113] Apply suggestions from code review, formatting fixes Signed-off-by: Pierre R. Mai --- osi_logicallane.proto | 21 +++++++++++++++------ 1 file changed, 15 insertions(+), 6 deletions(-) diff --git a/osi_logicallane.proto b/osi_logicallane.proto index 3bdee257e..fc5d9f86a 100644 --- a/osi_logicallane.proto +++ b/osi_logicallane.proto @@ -886,12 +886,19 @@ message LogicalLane // The starting point of the traffic rule validity on the lane. // Must be in range [\c sStart,\c sEnd] of the reference line. // + // Note: The traffic rule applies only to traffic with notional + // direction of travel from the start_s coordinate towards + // the end_s coordinate. For unidirectional lanes this must + // match the direction of travel as specified by the + // move_direction field of the logical lane. For bidirectional + // lanes this allows the specification of separate rules for + // each direction of travel. + // optional double start_s = 1; // // The ending point of the traffic rule validity on the lane. // Must be in range [\c sStart,\c sEnd] of the reference line. - // Note: Should always be greater than the starting point. // optional double end_s = 2; @@ -913,16 +920,18 @@ message LogicalLane optional MovingObject.Type type = 1; // - // Vehicle classification type for traffic participants - // Should be set to UNKNOWN if type is not TYPE_VEHICLE or the rule - // is valid for all vehicle types. + // Vehicle classification type for traffic participants. + // + // Should be set to TYPE_UNKNOWN if type is not TYPE_VEHICLE + // or the rule is valid for all vehicle types. // optional MovingObject.VehicleClassification.Type vehicle_type = 2; // // Role of traffic participant. - // Should be set to UNKNOWN if type is not TYPE_VEHICLE or the rule - // is valid for all vehicle roles. + // + // Should be set to ROLE_UNKNOWN if type is not TYPE_VEHICLE + // or the rule is valid for all vehicle roles. // optional MovingObject.VehicleClassification.Role vehicle_role = 3; } From 974314382d4b17ae8fb3ca5c1d78b776b432458f Mon Sep 17 00:00:00 2001 From: "Pierre R. Mai" Date: Fri, 5 Apr 2024 19:56:31 +0200 Subject: [PATCH 087/113] Update VERSION for release 3.7.0 Signed-off-by: Pierre R. Mai --- VERSION | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/VERSION b/VERSION index 24beea772..ffc0deabd 100644 --- a/VERSION +++ b/VERSION @@ -1,3 +1,3 @@ VERSION_MAJOR = 3 -VERSION_MINOR = 6 +VERSION_MINOR = 7 VERSION_PATCH = 0 From 2ab8122b65f42883699352bf9aeccdc11b26858b Mon Sep 17 00:00:00 2001 From: "Pierre R. Mai" Date: Wed, 3 Apr 2024 14:10:04 +0200 Subject: [PATCH 088/113] Add initial TestPyPI package publishing Signed-off-by: Pierre R. Mai --- .github/workflows/protobuf.yml | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/.github/workflows/protobuf.yml b/.github/workflows/protobuf.yml index 40923dd62..501fb8ac3 100644 --- a/.github/workflows/protobuf.yml +++ b/.github/workflows/protobuf.yml @@ -26,6 +26,9 @@ jobs: runs-on: ubuntu-22.04 + permissions: + id-token: write + steps: - name: Checkout OSI uses: actions/checkout@v4 @@ -137,6 +140,11 @@ jobs: name: python-dist path: dist/ + - name: Publish Snapshot Release on TestPyPI + uses: pypa/gh-action-pypi-publish@release/v1 + with: + repository-url: https://test.pypi.org/legacy/ + - name: Deploy to gh-pages if push to master branch if: ${{ github.event_name == 'push' && github.ref == 'refs/heads/master' }} uses: peaceiris/actions-gh-pages@v3 From e9385ac7d55569ad0e7ba34942b4e74d35a97ba8 Mon Sep 17 00:00:00 2001 From: "Pierre R. Mai" Date: Fri, 5 Apr 2024 22:18:46 +0200 Subject: [PATCH 089/113] Split python publishing into separate job Signed-off-by: Pierre R. Mai --- .github/workflows/protobuf.yml | 34 +++++++++++++++++++++++++--------- 1 file changed, 25 insertions(+), 9 deletions(-) diff --git a/.github/workflows/protobuf.yml b/.github/workflows/protobuf.yml index 501fb8ac3..0a6401455 100644 --- a/.github/workflows/protobuf.yml +++ b/.github/workflows/protobuf.yml @@ -26,9 +26,6 @@ jobs: runs-on: ubuntu-22.04 - permissions: - id-token: write - steps: - name: Checkout OSI uses: actions/checkout@v4 @@ -134,17 +131,12 @@ jobs: if-no-files-found: error - name: Upload Python Distribution - if: ${{ github.event_name == 'pull_request' }} + if: ${{ github.event_name == 'pull_request' || ( github.event_name == 'push' && github.ref == 'refs/heads/master' ) }} uses: actions/upload-artifact@v4 with: name: python-dist path: dist/ - - name: Publish Snapshot Release on TestPyPI - uses: pypa/gh-action-pypi-publish@release/v1 - with: - repository-url: https://test.pypi.org/legacy/ - - name: Deploy to gh-pages if push to master branch if: ${{ github.event_name == 'push' && github.ref == 'refs/heads/master' }} uses: peaceiris/actions-gh-pages@v3 @@ -232,3 +224,27 @@ jobs: - name: Run Python Tests run: python -m unittest discover tests + + publish-python-dist: + name: Publish Python Distribution + + runs-on: ubuntu-22.04 + + permissions: + id-token: write + + needs: [build-proto2-linux64, build-proto3-linux64] + + if: ${{ github.event_name == 'push' && github.ref == 'refs/heads/master' }} + + steps: + - name: Download Distribution + uses: actions/download-artifact@v4 + with: + name: python-dist + path: dist/ + + - name: Publish Snapshot Release on TestPyPI + uses: pypa/gh-action-pypi-publish@release/v1 + with: + repository-url: https://test.pypi.org/legacy/ From 296023a20d15bc8d24f4a5e82c31232c97acb67f Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 25 Mar 2024 11:36:12 +0000 Subject: [PATCH 090/113] Bump black from 23.12.1 to 24.3.0 Bumps [black](https://github.com/psf/black) from 23.12.1 to 24.3.0. - [Release notes](https://github.com/psf/black/releases) - [Changelog](https://github.com/psf/black/blob/main/CHANGES.md) - [Commits](https://github.com/psf/black/compare/23.12.1...24.3.0) --- updated-dependencies: - dependency-name: black dependency-type: direct:development ... Signed-off-by: dependabot[bot] --- requirements_tests.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements_tests.txt b/requirements_tests.txt index 43e06de0a..4872aecca 100644 --- a/requirements_tests.txt +++ b/requirements_tests.txt @@ -1,2 +1,2 @@ pyyaml -black==23.12.1 +black==24.3.0 From c19320ff9656d5b20a084c63a96e8c5400ec548f Mon Sep 17 00:00:00 2001 From: "Pierre R. Mai" Date: Fri, 26 Apr 2024 14:07:57 +0200 Subject: [PATCH 091/113] Fix indentation regression due to updated black Signed-off-by: Pierre R. Mai --- osi3trace/osi_trace.py | 1 + 1 file changed, 1 insertion(+) diff --git a/osi3trace/osi_trace.py b/osi3trace/osi_trace.py index 49453c660..4d0699dbf 100644 --- a/osi3trace/osi_trace.py +++ b/osi3trace/osi_trace.py @@ -1,6 +1,7 @@ """ Module to handle and manage OSI trace files. """ + import lzma import struct From de54ef7c20a2ec25f5285604c701c185b808e44f Mon Sep 17 00:00:00 2001 From: "Pierre R. Mai" Date: Fri, 5 Apr 2024 15:34:11 +0200 Subject: [PATCH 092/113] Add test for osi3trace offset reading robustness Signed-off-by: Pierre R. Mai --- tests/test_osi_trace.py | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/tests/test_osi_trace.py b/tests/test_osi_trace.py index 8a9a430ec..428cecbb5 100644 --- a/tests/test_osi_trace.py +++ b/tests/test_osi_trace.py @@ -22,6 +22,20 @@ def test_osi_trace(self): self.assertTrue(os.path.exists(path_output)) + def test_osi_trace_offsets_robustness(self): + with tempfile.TemporaryDirectory() as tmpdirname: + path_input = os.path.join(tmpdirname, "input.osi") + create_sample(path_input) + + trace = OSITrace(path_input) + # Test whether the function can handle be run multiple times safely + offsets = trace.retrieve_offsets(None) + offsets2 = trace.retrieve_offsets(None) + trace.close() + + self.assertEqual(len(offsets), 10) + self.assertEqual(offsets, offsets2) + def create_sample(path): f = open(path, "ab") From ee47d4906b67baca9987152b062103e746ae4e36 Mon Sep 17 00:00:00 2001 From: "Pierre R. Mai" Date: Fri, 5 Apr 2024 16:02:22 +0200 Subject: [PATCH 093/113] Fix precedence error in retrieve_offsets As noted by @ClemensLinnhoff there is a precedence error in retrieve_offsets of osi3trace which results in errors if the function is called again after a complete read. Signed-off-by: Pierre R. Mai --- osi3trace/osi_trace.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/osi3trace/osi_trace.py b/osi3trace/osi_trace.py index 4d0699dbf..2b54e6d44 100644 --- a/osi3trace/osi_trace.py +++ b/osi3trace/osi_trace.py @@ -55,8 +55,8 @@ def retrieve_offsets(self, limit=None): if not self.read_complete: self.current_index = len(self.message_offsets) - 1 self.file.seek(self.message_offsets[-1], 0) - while ( - not self.read_complete and not limit or len(self.message_offsets) <= limit + while not self.read_complete and ( + not limit or len(self.message_offsets) <= limit ): self.retrieve_message(skip=True) return self.message_offsets From 7d588c6c0944ab7c9a2f751d16f81a2acf0a2f85 Mon Sep 17 00:00:00 2001 From: Fabian Pfeuffer Date: Mon, 18 Mar 2024 09:38:38 +0100 Subject: [PATCH 094/113] Improve omit_static_information field description Signed-off-by: Fabian Pfeuffer --- osi_sensorviewconfiguration.proto | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/osi_sensorviewconfiguration.proto b/osi_sensorviewconfiguration.proto index 4601d1bc6..1764cbb1b 100644 --- a/osi_sensorviewconfiguration.proto +++ b/osi_sensorviewconfiguration.proto @@ -201,10 +201,15 @@ message SensorViewConfiguration // Omit Static Information // // This flag specifies whether \c GroundTruth information that - // was already provided using a GroundTruthInit parameter + // was already provided using a + // OMSP GroundTruthInit parameter // at initialization time shall be omitted from the \c SensorView // ground truth information. // + // Setting the \c #omit_static_information field allows a clear split between the dynamic + // simulation data, which is contained by ground truth messages with the \c #omit_static_information + // flag, and the static simulation data, which is contained in the OSMP GroundTruthInit. + // optional bool omit_static_information = 11; // Generic Sensor View Configuration(s). From ffc2e8cb651f612b93e22a3d8dd4b0b452fea726 Mon Sep 17 00:00:00 2001 From: Fabian Pfeuffer Date: Thu, 21 Mar 2024 09:40:19 +0100 Subject: [PATCH 095/113] Fixed minor spelling mistake Signed-off-by: Fabian Pfeuffer --- osi_sensorviewconfiguration.proto | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osi_sensorviewconfiguration.proto b/osi_sensorviewconfiguration.proto index 1764cbb1b..df6e3f0f7 100644 --- a/osi_sensorviewconfiguration.proto +++ b/osi_sensorviewconfiguration.proto @@ -202,7 +202,7 @@ message SensorViewConfiguration // // This flag specifies whether \c GroundTruth information that // was already provided using a - // OMSP GroundTruthInit parameter + // OSMP GroundTruthInit parameter // at initialization time shall be omitted from the \c SensorView // ground truth information. // From ce85f1124539a7040f4489e8ad89513403583dd8 Mon Sep 17 00:00:00 2001 From: Thomas Sedlmayer Date: Fri, 22 Mar 2024 13:47:03 +0100 Subject: [PATCH 096/113] Mark OSMP as example for ground truth init Signed-off-by: Thomas Sedlmayer --- osi_sensorviewconfiguration.proto | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/osi_sensorviewconfiguration.proto b/osi_sensorviewconfiguration.proto index df6e3f0f7..fe5b46869 100644 --- a/osi_sensorviewconfiguration.proto +++ b/osi_sensorviewconfiguration.proto @@ -201,14 +201,14 @@ message SensorViewConfiguration // Omit Static Information // // This flag specifies whether \c GroundTruth information that - // was already provided using a - // OSMP GroundTruthInit parameter + // was already provided using a GroundTruthInit parameter (e.g. OSMP GroundTruthInit) // at initialization time shall be omitted from the \c SensorView // ground truth information. // - // Setting the \c #omit_static_information field allows a clear split between the dynamic - // simulation data, which is contained by ground truth messages with the \c #omit_static_information - // flag, and the static simulation data, which is contained in the OSMP GroundTruthInit. + // Setting the \c #omit_static_information field allows a clear split + // between the dynamic simulation data, which is contained by ground truth + // messages with the \c #omit_static_information flag, and the static + // simulation data, which is contained in the (OSMP) GroundTruthInit. // optional bool omit_static_information = 11; From 8f999532dc6e7d99d5401b1c3a183b9273f6bfdc Mon Sep 17 00:00:00 2001 From: "Pierre R. Mai" Date: Fri, 22 Mar 2024 16:31:43 +0100 Subject: [PATCH 097/113] Grammar fix from review Signed-off-by: Pierre R. Mai --- osi_sensorviewconfiguration.proto | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osi_sensorviewconfiguration.proto b/osi_sensorviewconfiguration.proto index fe5b46869..48bfd8f8c 100644 --- a/osi_sensorviewconfiguration.proto +++ b/osi_sensorviewconfiguration.proto @@ -206,7 +206,7 @@ message SensorViewConfiguration // ground truth information. // // Setting the \c #omit_static_information field allows a clear split - // between the dynamic simulation data, which is contained by ground truth + // between the dynamic simulation data, which is contained in ground truth // messages with the \c #omit_static_information flag, and the static // simulation data, which is contained in the (OSMP) GroundTruthInit. // From fd93999decdb1901ba780c496f2b0835f3b0f445 Mon Sep 17 00:00:00 2001 From: "Pierre R. Mai" Date: Wed, 3 Apr 2024 18:04:29 +0200 Subject: [PATCH 098/113] Update and harmonize python installation instructions Signed-off-by: Pierre R. Mai --- doc/setup/installing_linux_python.adoc | 38 ++++++++++++++++-------- doc/setup/installing_windows_python.adoc | 32 ++++++++++++++++++-- 2 files changed, 56 insertions(+), 14 deletions(-) diff --git a/doc/setup/installing_linux_python.adoc b/doc/setup/installing_linux_python.adoc index b1b84a32c..de234498f 100644 --- a/doc/setup/installing_linux_python.adoc +++ b/doc/setup/installing_linux_python.adoc @@ -4,12 +4,31 @@ include::{root-path}_config.adoc[] endif::[] = Installing OSI for Python on Linux +== Installing from PyPI + +Steps:: + +. Open a terminal. ++ +. Optionally create and activate a new virtual environment. ++ +---- +python3 -m venv venv +source venv/bin/activate +---- ++ +. Install Open Simulation Interface. ++ +---- +pip install open-simulation-interface +---- + +== Installing from source + *Prerequisites:: * You have installed everything described in <>. -* You have installed _pip3_. -* You have installed _python-setuptools_. -* For a local installation, you have installed _virtualenv_. +* You have installed _pip_. Steps:: @@ -26,15 +45,10 @@ git clone https://github.com/OpenSimulationInterface/open-simulation-interface.g cd open-simulation-interface ---- + -. Create a new virtual environment. -+ ----- -virtualenv -p python3 venv ----- -+ -. Activate the virtual environment. +. Optionally create and activate a new virtual environment. + ---- +python3 -m venv venv source venv/bin/activate ---- + @@ -42,11 +56,11 @@ source venv/bin/activate .. Local installation + ---- -python3 -m pip install . +pip install . ---- + .. Global installation + ---- -sudo pip3 install . +sudo pip install . ---- diff --git a/doc/setup/installing_windows_python.adoc b/doc/setup/installing_windows_python.adoc index ecb3d31cf..37a2bba30 100644 --- a/doc/setup/installing_windows_python.adoc +++ b/doc/setup/installing_windows_python.adoc @@ -4,6 +4,27 @@ include::{root-path}_config.adoc[] endif::[] = Installing OSI for Python on Windows +== Installing from PyPI + +Steps:: + +. Open a terminal. ++ +. Optionally create and activate a new virtual environment. ++ +---- +python -m venv venv +venv\Scripts\activate +---- ++ +. Install Open Simulation Interface. ++ +---- +pip install open-simulation-interface +---- + +== Installing from source + Prerequisites:: * You have installed everything described in <>. @@ -25,8 +46,15 @@ git clone https://github.com/OpenSimulationInterface/open-simulation-interface.g cd open-simulation-interface ---- + -. Run the setup script. +. Optionally create and activate a new virtual environment. ++ +---- +python -m venv venv +venv\Scripts\activate +---- ++ +. Install Open Simulation Interface. + ---- -python setup.py install +pip install . ---- From f4fce5310a3f0a7a47139bc3ab04367882f8433f Mon Sep 17 00:00:00 2001 From: Thomas Sedlmayer Date: Mon, 15 Apr 2024 11:51:07 +0200 Subject: [PATCH 099/113] Fix outdated documentation on formatting scripts Signed-off-by: Thomas Sedlmayer --- ...rmatting_scripts.adoc => formatting_script.adoc} | 13 ++++--------- doc/open-simulation-interface_user_guide.adoc | 2 +- 2 files changed, 5 insertions(+), 10 deletions(-) rename doc/architecture/{formatting_scripts.adoc => formatting_script.adoc} (61%) diff --git a/doc/architecture/formatting_scripts.adoc b/doc/architecture/formatting_script.adoc similarity index 61% rename from doc/architecture/formatting_scripts.adoc rename to doc/architecture/formatting_script.adoc index a953b3e13..d8beec595 100644 --- a/doc/architecture/formatting_scripts.adoc +++ b/doc/architecture/formatting_script.adoc @@ -2,10 +2,10 @@ ifndef::include-only-once[] :root-path: ../ include::{root-path}_config.adoc[] endif::[] -= Trace-file formatting scripts += Trace-file formatting script -The OSI repository contains Python scripts for converting trace files from one format to another. -The formatting scripts are stored in `open-simulation-interface/format/` +The OSI repository contains a Python script for converting trace files from one format to another. +The formatting script is stored in `open-simulation-interface/osi3trace/`. **osi2read.py** @@ -22,12 +22,7 @@ The default value is `'SensorView'`. `--output`, `-o`:: Optional string containing the name of the output file. -The default value is `'converted.txth'`. - -`--format`, `-f`:: -Optional string containing the format type of the trace file. -`'separated'`, or `None` are permitted values. -The default value is `None`. +The default value is `None`, in which case the output file name is set to the name of the input file, with the file extension being replaced by `.txth`. **Related topics** diff --git a/doc/open-simulation-interface_user_guide.adoc b/doc/open-simulation-interface_user_guide.adoc index f45cc65c2..69296d267 100644 --- a/doc/open-simulation-interface_user_guide.adoc +++ b/doc/open-simulation-interface_user_guide.adoc @@ -69,7 +69,7 @@ include::./architecture/trace_file_naming.adoc[leveloffset=+3] include::./architecture/trace_file_example.adoc[leveloffset=+3] -include::./architecture/formatting_scripts.adoc[leveloffset=+3] +include::./architecture/formatting_script.adoc[leveloffset=+3] // Setting up OSI From 70d830ed95beabc0388adc31fb815219976393bb Mon Sep 17 00:00:00 2001 From: ClemensLinnhoff Date: Fri, 3 May 2024 09:21:38 +0200 Subject: [PATCH 100/113] Add rules according to notes in the documentation Signed-off-by: ClemensLinnhoff --- osi_common.proto | 6 +++++- osi_detectedobject.proto | 12 ++++++++++++ osi_route.proto | 1 + osi_trafficcommand.proto | 5 +++++ 4 files changed, 23 insertions(+), 1 deletion(-) diff --git a/osi_common.proto b/osi_common.proto index 7db75ca7a..c820790b2 100644 --- a/osi_common.proto +++ b/osi_common.proto @@ -235,7 +235,7 @@ message ExternalReference // The type of the external references. // - // Mandatory value describing the type of the original source. + // Value describing the type of the original source. // // For OpenX/ASAM standards it is specified as follows: // - net.asam.opendrive @@ -245,6 +245,10 @@ message ExternalReference // reverse domain name notation with lower-case type field // is recommended to guarantee unique and interoperable identification. // + // \rules + // is_set + // \endrules + // optional string type = 2; // The external identifier reference value. diff --git a/osi_detectedobject.proto b/osi_detectedobject.proto index fb4e4e62b..3ea53c4e0 100644 --- a/osi_detectedobject.proto +++ b/osi_detectedobject.proto @@ -325,6 +325,10 @@ message DetectedMovingObject // \note This field is mandatory if the \c CandidateMovingObject::type // is \c MovingObject::TYPE_VEHICLE . // + // \rules + // check_if this.type is_equal_to 2 else do_check is_set + // \endrules + // optional MovingObject.VehicleClassification vehicle_classification = 3; // Pedestrian head pose for behavior prediction. Describes the head @@ -339,6 +343,10 @@ message DetectedMovingObject // \note This field is mandatory if the \c CandidateMovingObject.type is // \c MovingObject::TYPE_PEDESTRIAN // + // \rules + // check_if this.type is_equal_to 3 else do_check is_set + // \endrules + // // \par Reference: // // [1] Patton, K. T. & Thibodeau, G. A. (2015). Anatomy & Physiology. 9th Edition. Elsevier. Missouri, U.S.A. ISBN 978-0-323-34139-4. p. 1229. @@ -358,6 +366,10 @@ message DetectedMovingObject // \note This field is mandatory if the \c CandidateMovingObject::type // is \c MovingObject::TYPE_PEDESTRIAN // + // \rules + // check_if this.type is_equal_to 3 else do_check is_set + // \endrules + // // \par Reference: // [1] Patton, K. T. & Thibodeau, G. A. (2015). Anatomy & Physiology. 9th Edition. Elsevier. Missouri, U.S.A. ISBN 978-0-323-34139-4. p. 1229. // diff --git a/osi_route.proto b/osi_route.proto index 794c6bb20..21b478ff3 100644 --- a/osi_route.proto +++ b/osi_route.proto @@ -42,6 +42,7 @@ message Route // // \rules // is_set + // is_globally_unique // \endrules // optional Identifier route_id = 1; diff --git a/osi_trafficcommand.proto b/osi_trafficcommand.proto index 61c62a9b6..fc0e5b866 100644 --- a/osi_trafficcommand.proto +++ b/osi_trafficcommand.proto @@ -142,6 +142,11 @@ message TrafficAction // \note This id must be unique within all traffic command // messages exchanged with one traffic participant. // + // \rules + // is_set + // is_globally_unique + // \endrules + // optional Identifier action_id = 1; } From 6d61dce5cf0866b0b6873e4e296c86ebd8229fed Mon Sep 17 00:00:00 2001 From: Clemens Linnhoff Date: Mon, 6 May 2024 09:51:08 +0200 Subject: [PATCH 101/113] Apply suggestions from code review Co-authored-by: Pierre R. Mai Signed-off-by: Clemens Linnhoff --- osi_common.proto | 2 +- osi_route.proto | 1 - osi_trafficcommand.proto | 1 - 3 files changed, 1 insertion(+), 3 deletions(-) diff --git a/osi_common.proto b/osi_common.proto index c820790b2..804c39805 100644 --- a/osi_common.proto +++ b/osi_common.proto @@ -235,7 +235,7 @@ message ExternalReference // The type of the external references. // - // Value describing the type of the original source. + // Mandatory value describing the type of the original source. // // For OpenX/ASAM standards it is specified as follows: // - net.asam.opendrive diff --git a/osi_route.proto b/osi_route.proto index 21b478ff3..794c6bb20 100644 --- a/osi_route.proto +++ b/osi_route.proto @@ -42,7 +42,6 @@ message Route // // \rules // is_set - // is_globally_unique // \endrules // optional Identifier route_id = 1; diff --git a/osi_trafficcommand.proto b/osi_trafficcommand.proto index fc0e5b866..d8763b430 100644 --- a/osi_trafficcommand.proto +++ b/osi_trafficcommand.proto @@ -144,7 +144,6 @@ message TrafficAction // // \rules // is_set - // is_globally_unique // \endrules // optional Identifier action_id = 1; From de45ac8eb76a7f92bd394c5405c717b753a1c988 Mon Sep 17 00:00:00 2001 From: ClemensLinnhoff Date: Mon, 6 May 2024 10:11:42 +0200 Subject: [PATCH 102/113] Remove spaces at end of line Signed-off-by: ClemensLinnhoff --- osi_common.proto | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osi_common.proto b/osi_common.proto index 804c39805..a4e62071a 100644 --- a/osi_common.proto +++ b/osi_common.proto @@ -249,7 +249,7 @@ message ExternalReference // is_set // \endrules // - optional string type = 2; + optional string type = 2; // The external identifier reference value. // From c07e10208f9931492ec6ab34d25202183f72a40e Mon Sep 17 00:00:00 2001 From: "Pierre R. Mai" Date: Fri, 5 Apr 2024 22:56:10 +0200 Subject: [PATCH 103/113] Add full release publication of python packages Signed-off-by: Pierre R. Mai --- .github/workflows/protobuf.yml | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/.github/workflows/protobuf.yml b/.github/workflows/protobuf.yml index 0a6401455..0e15a3ed3 100644 --- a/.github/workflows/protobuf.yml +++ b/.github/workflows/protobuf.yml @@ -131,7 +131,7 @@ jobs: if-no-files-found: error - name: Upload Python Distribution - if: ${{ github.event_name == 'pull_request' || ( github.event_name == 'push' && github.ref == 'refs/heads/master' ) }} + if: ${{ github.event_name == 'pull_request' || ( github.event_name == 'push' && ( github.ref == 'refs/heads/master' || startsWith(github.ref, 'refs/tags/v') ) ) }} uses: actions/upload-artifact@v4 with: name: python-dist @@ -235,7 +235,7 @@ jobs: needs: [build-proto2-linux64, build-proto3-linux64] - if: ${{ github.event_name == 'push' && github.ref == 'refs/heads/master' }} + if: ${{ github.event_name == 'push' && ( github.ref == 'refs/heads/master' || startsWith(github.ref, 'refs/tags/v') ) }} steps: - name: Download Distribution @@ -248,3 +248,7 @@ jobs: uses: pypa/gh-action-pypi-publish@release/v1 with: repository-url: https://test.pypi.org/legacy/ + + - name: Publish Full Release on PyPI + if: startsWith(github.ref, 'refs/tags/v') + uses: pypa/gh-action-pypi-publish@release/v1 From daf0e7aca182f55cf65f561f9607bf37e4f3dcec Mon Sep 17 00:00:00 2001 From: "Pierre R. Mai" Date: Mon, 13 May 2024 10:25:00 +0200 Subject: [PATCH 104/113] Clarify handling of purely technical IDs Addresses #809. Signed-off-by: Pierre R. Mai --- osi_common.proto | 3 +++ osi_sensorview.proto | 1 - rules.yml | 2 +- 3 files changed, 4 insertions(+), 2 deletions(-) diff --git a/osi_common.proto b/osi_common.proto index a4e62071a..cd49951a6 100644 --- a/osi_common.proto +++ b/osi_common.proto @@ -197,6 +197,9 @@ message Orientation3d // available address space is exhausted and the specific values have not been in // use for several time steps. Sensor specific tracking IDs have no restrictions // and should behave according to the sensor specifications. +// Purely simulation technical IDs, like sensor IDs, are not required to be +// unique among all simulated items, but rather unique within the context of the +// given message type. // // The value MAX(uint64) = 2^(64) -1 = // 0b1111111111111111111111111111111111111111111111111111111111111111 is diff --git a/osi_sensorview.proto b/osi_sensorview.proto index 84e4cf4c3..68973fbf1 100644 --- a/osi_sensorview.proto +++ b/osi_sensorview.proto @@ -65,7 +65,6 @@ message SensorView // which are used in the detected features. // // \rules - // is_globally_unique // is_set // \endrules // diff --git a/rules.yml b/rules.yml index 1816a7542..41db521c3 100644 --- a/rules.yml +++ b/rules.yml @@ -10,4 +10,4 @@ is_iso_country_code: '^[ ]\b(is_iso_country_code)\b' first_element: '^[ ]\b(first_element)\b' last_element: '^[ ]\b(last_element)\b' check_if: '^[ ](\bcheck_if\b)(.*\belse do_check\b)' -is_set: '^[ ]\b(is_set)\b' \ No newline at end of file +is_set: '^[ ]\b(is_set)\b' From 51638638fee31cd85f2745bb7611c222240cdcfa Mon Sep 17 00:00:00 2001 From: Thomas Hempen Date: Wed, 8 May 2024 15:51:35 +0200 Subject: [PATCH 105/113] Update trace_file_naming.adoc Added hvd as a supported trace file type for HostVehicleData Signed-off-by: Thomas Hempen --- doc/architecture/trace_file_naming.adoc | 2 ++ 1 file changed, 2 insertions(+) diff --git a/doc/architecture/trace_file_naming.adoc b/doc/architecture/trace_file_naming.adoc index bbc892422..2c4bf46da 100644 --- a/doc/architecture/trace_file_naming.adoc +++ b/doc/architecture/trace_file_naming.adoc @@ -29,6 +29,8 @@ Trace file contains `TrafficUpdate` messages. `tc`:: Trace file contains `TrafficCommand` messages. +`hvd`:: +Trace file contains `HostVehicleData` messages. **Example** From bc7453e6dc4059d3fb03e4c02c860a797266682e Mon Sep 17 00:00:00 2001 From: "Pierre R. Mai" Date: Mon, 13 May 2024 11:56:46 +0200 Subject: [PATCH 106/113] Adjust minimum protobuf requirement (fix #807) Signed-off-by: Pierre R. Mai --- doc/setup/installing_prerequisites.adoc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/doc/setup/installing_prerequisites.adoc b/doc/setup/installing_prerequisites.adoc index 00bd6fb90..430499bed 100644 --- a/doc/setup/installing_prerequisites.adoc +++ b/doc/setup/installing_prerequisites.adoc @@ -51,7 +51,7 @@ vcpkg install --triplet=x64-windows-static-md protobuf Dynamic linking (NOT RECOMMENDED):: As already mentioned, shared linking is possible on Linux, but NOT RECOMMENDED. -However, for dynamic linking install _protobuf_ (version 3.0.0 or higher) with apt: +However, for dynamic linking install _protobuf_ (version 2.6.1 or higher) with apt: ---- sudo apt-get install libprotobuf-dev protobuf-compiler ---- @@ -64,7 +64,7 @@ This means that your OSI is build statically but still linking dynamically again Here, again either _protobuf_ has to build statically from source or some solution e.g. vcpkg needs to be utilized. We recommend the following (as in the README of the OSI project): -Install _protobuf_ (version 3.0.0 or higher) from source with `CXXFLAGS="-fPIC"` to allow static linking of your OSI FMUs (replace with preferred release): +Install _protobuf_ (version 2.6.1 or higher) from source with `CXXFLAGS="-fPIC"` to allow static linking of your OSI FMUs (replace with preferred release): ---- wget https://github.com/protocolbuffers/protobuf/releases/download//protobuf-all-.tar.gz tar -xzf protobuf-all-.tar.gz From 27df0e44be2fd0c08dcebfe32b6169fedb530a0b Mon Sep 17 00:00:00 2001 From: ClemensLinnhoff Date: Mon, 27 May 2024 15:27:34 +0200 Subject: [PATCH 107/113] Add three more top-level messages Signed-off-by: ClemensLinnhoff --- osi3trace/osi2read.py | 2 +- osi3trace/osi_trace.py | 6 ++++++ 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/osi3trace/osi2read.py b/osi3trace/osi2read.py index c6bee861e..7ad96a902 100644 --- a/osi3trace/osi2read.py +++ b/osi3trace/osi2read.py @@ -28,7 +28,7 @@ def command_line_arguments(): "--type", "-t", help="Name of the type used to serialize data.", - choices=["SensorView", "GroundTruth", "SensorData"], + choices=["SensorView", "GroundTruth", "SensorData", "TrafficUpdate", "TrafficCommand", "TrafficCommandUpdate"], default="SensorView", type=str, required=False, diff --git a/osi3trace/osi_trace.py b/osi3trace/osi_trace.py index 2b54e6d44..70a36021b 100644 --- a/osi3trace/osi_trace.py +++ b/osi3trace/osi_trace.py @@ -8,12 +8,18 @@ from osi3.osi_sensorview_pb2 import SensorView from osi3.osi_groundtruth_pb2 import GroundTruth from osi3.osi_sensordata_pb2 import SensorData +from osi3.osi_trafficupdate_pb2 import TrafficUpdate +from osi3.osi_trafficcommand_pb2 import TrafficCommand +from osi3.osi_trafficcommandupdate_pb2 import TrafficCommandUpdate MESSAGES_TYPE = { "SensorView": SensorView, "GroundTruth": GroundTruth, "SensorData": SensorData, + "TrafficUpdate": TrafficUpdate, + "TrafficCommand": TrafficCommand, + "TrafficCommandUpdate": TrafficCommandUpdate } From 8f5a8fc5d80ce646c770d34b905a5f7f0a3c3d20 Mon Sep 17 00:00:00 2001 From: ClemensLinnhoff Date: Mon, 27 May 2024 15:32:17 +0200 Subject: [PATCH 108/113] Formatting Signed-off-by: ClemensLinnhoff --- osi3trace/osi2read.py | 9 ++++++++- osi3trace/osi_trace.py | 2 +- 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/osi3trace/osi2read.py b/osi3trace/osi2read.py index 7ad96a902..d987ec5b0 100644 --- a/osi3trace/osi2read.py +++ b/osi3trace/osi2read.py @@ -28,7 +28,14 @@ def command_line_arguments(): "--type", "-t", help="Name of the type used to serialize data.", - choices=["SensorView", "GroundTruth", "SensorData", "TrafficUpdate", "TrafficCommand", "TrafficCommandUpdate"], + choices=[ + "SensorView", + "GroundTruth", + "SensorData", + "TrafficUpdate", + "TrafficCommand", + "TrafficCommandUpdate", + ], default="SensorView", type=str, required=False, diff --git a/osi3trace/osi_trace.py b/osi3trace/osi_trace.py index 70a36021b..43d66029c 100644 --- a/osi3trace/osi_trace.py +++ b/osi3trace/osi_trace.py @@ -19,7 +19,7 @@ "SensorData": SensorData, "TrafficUpdate": TrafficUpdate, "TrafficCommand": TrafficCommand, - "TrafficCommandUpdate": TrafficCommandUpdate + "TrafficCommandUpdate": TrafficCommandUpdate, } From 91cc877c599f1be4630f4f3bf14620113d86d8f1 Mon Sep 17 00:00:00 2001 From: "Pierre R. Mai" Date: Sun, 9 Jun 2024 19:58:16 +0200 Subject: [PATCH 109/113] Add remaining missing top-level interfaces and tests Add all remaining top-level interfaces, fix documentation list of said interfaces and add tests for all interfaces to the osi_trace tests. Signed-off-by: Pierre R. Mai --- doc/architecture/architecture_overview.adoc | 2 +- osi3trace/osi2read.py | 11 +- osi3trace/osi_trace.py | 6 + tests/test_osi_trace.py | 441 +++++++++++++++++++- 4 files changed, 443 insertions(+), 17 deletions(-) diff --git a/doc/architecture/architecture_overview.adoc b/doc/architecture/architecture_overview.adoc index 7a9e98828..3e522947b 100644 --- a/doc/architecture/architecture_overview.adoc +++ b/doc/architecture/architecture_overview.adoc @@ -8,7 +8,7 @@ OSI contains an object-based environment description that uses the message forma Google developed and maintains the Protocol Buffer library. OSI defines top-level messages that are used to exchange data between separate models. Top-level messages define the `GroundTruth` interface, the `SensorData` interface, and – since OSI version 3.0.0 – the interfaces `SensorView` and `SensorViewConfiguration`. -Further top-level messages that were added in later versions of OSI are `TrafficCommand`, `TrafficUpdate`, `MotionRequest`, and `StreamingUpdate`. +Further top-level messages that were added in later versions of OSI are `TrafficCommand`, `TrafficCommandUpdate`, `TrafficUpdate`, `MotionRequest`, and `StreamingUpdate`. The following figure shows the interfaces and models involved in modeling a sensor. diff --git a/osi3trace/osi2read.py b/osi3trace/osi2read.py index d987ec5b0..4575d78b0 100644 --- a/osi3trace/osi2read.py +++ b/osi3trace/osi2read.py @@ -5,7 +5,7 @@ python3 osi2read.py -d trace.osi -o myreadableosifile """ -from osi3trace.osi_trace import OSITrace +from osi3trace.osi_trace import OSITrace, MESSAGES_TYPE import argparse import pathlib @@ -28,14 +28,7 @@ def command_line_arguments(): "--type", "-t", help="Name of the type used to serialize data.", - choices=[ - "SensorView", - "GroundTruth", - "SensorData", - "TrafficUpdate", - "TrafficCommand", - "TrafficCommandUpdate", - ], + choices=list(MESSAGES_TYPE.keys()), default="SensorView", type=str, required=False, diff --git a/osi3trace/osi_trace.py b/osi3trace/osi_trace.py index 43d66029c..541647b62 100644 --- a/osi3trace/osi_trace.py +++ b/osi3trace/osi_trace.py @@ -8,18 +8,24 @@ from osi3.osi_sensorview_pb2 import SensorView from osi3.osi_groundtruth_pb2 import GroundTruth from osi3.osi_sensordata_pb2 import SensorData +from osi3.osi_sensorviewconfiguration_pb2 import SensorViewConfiguration from osi3.osi_trafficupdate_pb2 import TrafficUpdate from osi3.osi_trafficcommand_pb2 import TrafficCommand from osi3.osi_trafficcommandupdate_pb2 import TrafficCommandUpdate +from osi3.osi_motionrequest_pb2 import MotionRequest +from osi3.osi_streamingupdate_pb2 import StreamingUpdate MESSAGES_TYPE = { "SensorView": SensorView, "GroundTruth": GroundTruth, "SensorData": SensorData, + "SensorViewConfiguration": SensorViewConfiguration, "TrafficUpdate": TrafficUpdate, "TrafficCommand": TrafficCommand, "TrafficCommandUpdate": TrafficCommandUpdate, + "MotionRequest": MotionRequest, + "StreamingUpdate": StreamingUpdate, } diff --git a/tests/test_osi_trace.py b/tests/test_osi_trace.py index 428cecbb5..93b0d7791 100644 --- a/tests/test_osi_trace.py +++ b/tests/test_osi_trace.py @@ -4,15 +4,24 @@ from osi3trace.osi_trace import OSITrace from osi3.osi_sensorview_pb2 import SensorView +from osi3.osi_groundtruth_pb2 import GroundTruth +from osi3.osi_sensordata_pb2 import SensorData +from osi3.osi_sensorviewconfiguration_pb2 import SensorViewConfiguration +from osi3.osi_trafficupdate_pb2 import TrafficUpdate +from osi3.osi_trafficcommand_pb2 import TrafficCommand +from osi3.osi_trafficcommandupdate_pb2 import TrafficCommandUpdate +from osi3.osi_motionrequest_pb2 import MotionRequest +from osi3.osi_streamingupdate_pb2 import StreamingUpdate + import struct class TestOSITrace(unittest.TestCase): - def test_osi_trace(self): + def test_osi_trace_sv(self): with tempfile.TemporaryDirectory() as tmpdirname: - path_output = os.path.join(tmpdirname, "output.txth") - path_input = os.path.join(tmpdirname, "input.osi") - create_sample(path_input) + path_output = os.path.join(tmpdirname, "output_sv.txth") + path_input = os.path.join(tmpdirname, "input_sv.osi") + create_sample_sv(path_input) trace = OSITrace(path_input) with open(path_output, "wt") as f: @@ -22,10 +31,122 @@ def test_osi_trace(self): self.assertTrue(os.path.exists(path_output)) + def test_osi_trace_gt(self): + with tempfile.TemporaryDirectory() as tmpdirname: + path_output = os.path.join(tmpdirname, "output_gt.txth") + path_input = os.path.join(tmpdirname, "input_gt.osi") + create_sample_gt(path_input) + + trace = OSITrace(path_input, "GroundTruth") + with open(path_output, "wt") as f: + for message in trace: + f.write(str(message)) + trace.close() + + self.assertTrue(os.path.exists(path_output)) + + def test_osi_trace_sd(self): + with tempfile.TemporaryDirectory() as tmpdirname: + path_output = os.path.join(tmpdirname, "output_sd.txth") + path_input = os.path.join(tmpdirname, "input_sd.osi") + create_sample_sd(path_input) + + trace = OSITrace(path_input, "SensorData") + with open(path_output, "wt") as f: + for message in trace: + f.write(str(message)) + trace.close() + + self.assertTrue(os.path.exists(path_output)) + + def test_osi_trace_svc(self): + with tempfile.TemporaryDirectory() as tmpdirname: + path_output = os.path.join(tmpdirname, "output_svc.txth") + path_input = os.path.join(tmpdirname, "input_svc.osi") + create_sample_svc(path_input) + + trace = OSITrace(path_input, "SensorViewConfiguration") + with open(path_output, "wt") as f: + for message in trace: + f.write(str(message)) + trace.close() + + self.assertTrue(os.path.exists(path_output)) + + def test_osi_trace_tu(self): + with tempfile.TemporaryDirectory() as tmpdirname: + path_output = os.path.join(tmpdirname, "output_tu.txth") + path_input = os.path.join(tmpdirname, "input_tu.osi") + create_sample_tu(path_input) + + trace = OSITrace(path_input, "TrafficUpdate") + with open(path_output, "wt") as f: + for message in trace: + f.write(str(message)) + trace.close() + + self.assertTrue(os.path.exists(path_output)) + + def test_osi_trace_tc(self): + with tempfile.TemporaryDirectory() as tmpdirname: + path_output = os.path.join(tmpdirname, "output_tc.txth") + path_input = os.path.join(tmpdirname, "input_tc.osi") + create_sample_tc(path_input) + + trace = OSITrace(path_input, "TrafficCommand") + with open(path_output, "wt") as f: + for message in trace: + f.write(str(message)) + trace.close() + + self.assertTrue(os.path.exists(path_output)) + + def test_osi_trace_tcu(self): + with tempfile.TemporaryDirectory() as tmpdirname: + path_output = os.path.join(tmpdirname, "output_tcu.txth") + path_input = os.path.join(tmpdirname, "input_tcu.osi") + create_sample_tcu(path_input) + + trace = OSITrace(path_input, "TrafficCommandUpdate") + with open(path_output, "wt") as f: + for message in trace: + f.write(str(message)) + trace.close() + + self.assertTrue(os.path.exists(path_output)) + + def test_osi_trace_mr(self): + with tempfile.TemporaryDirectory() as tmpdirname: + path_output = os.path.join(tmpdirname, "output_mr.txth") + path_input = os.path.join(tmpdirname, "input_mr.osi") + create_sample_mr(path_input) + + trace = OSITrace(path_input, "MotionRequest") + with open(path_output, "wt") as f: + for message in trace: + f.write(str(message)) + trace.close() + + self.assertTrue(os.path.exists(path_output)) + + def test_osi_trace_su(self): + with tempfile.TemporaryDirectory() as tmpdirname: + path_output = os.path.join(tmpdirname, "output_su.txth") + path_input = os.path.join(tmpdirname, "input_su.osi") + create_sample_su(path_input) + + trace = OSITrace(path_input, "StreamingUpdate") + with open(path_output, "wt") as f: + for message in trace: + f.write(str(message)) + trace.close() + + self.assertTrue(os.path.exists(path_output)) + def test_osi_trace_offsets_robustness(self): with tempfile.TemporaryDirectory() as tmpdirname: - path_input = os.path.join(tmpdirname, "input.osi") - create_sample(path_input) + path_input = os.path.join(tmpdirname, "input_robust.osi") + create_sample_sv(path_input) trace = OSITrace(path_input) # Test whether the function can handle be run multiple times safely @@ -37,10 +158,19 @@ def test_osi_trace_offsets_robustness(self): self.assertEqual(offsets, offsets2) -def create_sample(path): +def create_sample_sv(path): f = open(path, "ab") sensorview = SensorView() + sensorview.version.version_major = 3 + sensorview.version.version_minor = 0 + sensorview.version.version_patch = 0 + + sensorview.timestamp.seconds = 0 + sensorview.timestamp.nanos = 0 + + sensorview.sensor_id.value = 42 + sv_ground_truth = sensorview.global_ground_truth sv_ground_truth.version.version_major = 3 sv_ground_truth.version.version_minor = 0 @@ -55,6 +185,9 @@ def create_sample(path): # Generate 10 OSI messages for 9 seconds for i in range(10): # Increment the time + sensorview.timestamp.seconds += 1 + sensorview.timestamp.nanos += 100000 + sv_ground_truth.timestamp.seconds += 1 sv_ground_truth.timestamp.nanos += 100000 @@ -77,3 +210,297 @@ def create_sample(path): f.write(struct.pack(" Date: Mon, 10 Jun 2024 08:38:40 +0200 Subject: [PATCH 110/113] Refactor message type accessor, improve tests Signed-off-by: Pierre R. Mai --- osi3trace/osi2read.py | 4 ++-- osi3trace/osi_trace.py | 5 +++++ tests/test_osi_trace.py | 27 +++++++++++++++++++++++++++ 3 files changed, 34 insertions(+), 2 deletions(-) diff --git a/osi3trace/osi2read.py b/osi3trace/osi2read.py index 4575d78b0..a75bb9a76 100644 --- a/osi3trace/osi2read.py +++ b/osi3trace/osi2read.py @@ -5,7 +5,7 @@ python3 osi2read.py -d trace.osi -o myreadableosifile """ -from osi3trace.osi_trace import OSITrace, MESSAGES_TYPE +from osi3trace.osi_trace import OSITrace import argparse import pathlib @@ -28,7 +28,7 @@ def command_line_arguments(): "--type", "-t", help="Name of the type used to serialize data.", - choices=list(MESSAGES_TYPE.keys()), + choices=OSITrace.message_types(), default="SensorView", type=str, required=False, diff --git a/osi3trace/osi_trace.py b/osi3trace/osi_trace.py index 541647b62..1cc829bef 100644 --- a/osi3trace/osi_trace.py +++ b/osi3trace/osi_trace.py @@ -37,6 +37,11 @@ def map_message_type(type_name): """Map the type name to the protobuf message type.""" return MESSAGES_TYPE[type_name] + @staticmethod + def message_types(): + """Message types that OSITrace supports.""" + return list(MESSAGES_TYPE.keys()) + def __init__(self, path=None, type_name="SensorView", cache_messages=False): self.type = self.map_message_type(type_name) self.file = None diff --git a/tests/test_osi_trace.py b/tests/test_osi_trace.py index 93b0d7791..09240277b 100644 --- a/tests/test_osi_trace.py +++ b/tests/test_osi_trace.py @@ -26,7 +26,10 @@ def test_osi_trace_sv(self): trace = OSITrace(path_input) with open(path_output, "wt") as f: for message in trace: + self.assertIsInstance(message, SensorView) f.write(str(message)) + + self.assertEqual(len(trace.retrieve_offsets()), 10) trace.close() self.assertTrue(os.path.exists(path_output)) @@ -40,7 +43,10 @@ def test_osi_trace_gt(self): trace = OSITrace(path_input, "GroundTruth") with open(path_output, "wt") as f: for message in trace: + self.assertIsInstance(message, GroundTruth) f.write(str(message)) + + self.assertEqual(len(trace.retrieve_offsets()), 10) trace.close() self.assertTrue(os.path.exists(path_output)) @@ -54,7 +60,10 @@ def test_osi_trace_sd(self): trace = OSITrace(path_input, "SensorData") with open(path_output, "wt") as f: for message in trace: + self.assertIsInstance(message, SensorData) f.write(str(message)) + + self.assertEqual(len(trace.retrieve_offsets()), 10) trace.close() self.assertTrue(os.path.exists(path_output)) @@ -68,7 +77,10 @@ def test_osi_trace_svc(self): trace = OSITrace(path_input, "SensorViewConfiguration") with open(path_output, "wt") as f: for message in trace: + self.assertIsInstance(message, SensorViewConfiguration) f.write(str(message)) + + self.assertEqual(len(trace.retrieve_offsets()), 1) trace.close() self.assertTrue(os.path.exists(path_output)) @@ -82,7 +94,10 @@ def test_osi_trace_tu(self): trace = OSITrace(path_input, "TrafficUpdate") with open(path_output, "wt") as f: for message in trace: + self.assertIsInstance(message, TrafficUpdate) f.write(str(message)) + + self.assertEqual(len(trace.retrieve_offsets()), 10) trace.close() self.assertTrue(os.path.exists(path_output)) @@ -96,7 +111,10 @@ def test_osi_trace_tc(self): trace = OSITrace(path_input, "TrafficCommand") with open(path_output, "wt") as f: for message in trace: + self.assertIsInstance(message, TrafficCommand) f.write(str(message)) + + self.assertEqual(len(trace.retrieve_offsets()), 10) trace.close() self.assertTrue(os.path.exists(path_output)) @@ -110,7 +128,10 @@ def test_osi_trace_tcu(self): trace = OSITrace(path_input, "TrafficCommandUpdate") with open(path_output, "wt") as f: for message in trace: + self.assertIsInstance(message, TrafficCommandUpdate) f.write(str(message)) + + self.assertEqual(len(trace.retrieve_offsets()), 10) trace.close() self.assertTrue(os.path.exists(path_output)) @@ -124,7 +145,10 @@ def test_osi_trace_mr(self): trace = OSITrace(path_input, "MotionRequest") with open(path_output, "wt") as f: for message in trace: + self.assertIsInstance(message, MotionRequest) f.write(str(message)) + + self.assertEqual(len(trace.retrieve_offsets()), 10) trace.close() self.assertTrue(os.path.exists(path_output)) @@ -138,7 +162,10 @@ def test_osi_trace_su(self): trace = OSITrace(path_input, "StreamingUpdate") with open(path_output, "wt") as f: for message in trace: + self.assertIsInstance(message, StreamingUpdate) f.write(str(message)) + + self.assertEqual(len(trace.retrieve_offsets()), 10) trace.close() self.assertTrue(os.path.exists(path_output)) From af726652c560f38a092edc759243fa3f9b57a318 Mon Sep 17 00:00:00 2001 From: "Pierre R. Mai" Date: Mon, 10 Jun 2024 11:43:49 +0200 Subject: [PATCH 111/113] Add HostVehicleData support to OSITrace Closes #817. Signed-off-by: Pierre R. Mai --- doc/architecture/architecture_overview.adoc | 2 +- osi3trace/osi_trace.py | 2 + tests/test_osi_trace.py | 56 +++++++++++++++++++++ 3 files changed, 59 insertions(+), 1 deletion(-) diff --git a/doc/architecture/architecture_overview.adoc b/doc/architecture/architecture_overview.adoc index 3e522947b..31f28c154 100644 --- a/doc/architecture/architecture_overview.adoc +++ b/doc/architecture/architecture_overview.adoc @@ -8,7 +8,7 @@ OSI contains an object-based environment description that uses the message forma Google developed and maintains the Protocol Buffer library. OSI defines top-level messages that are used to exchange data between separate models. Top-level messages define the `GroundTruth` interface, the `SensorData` interface, and – since OSI version 3.0.0 – the interfaces `SensorView` and `SensorViewConfiguration`. -Further top-level messages that were added in later versions of OSI are `TrafficCommand`, `TrafficCommandUpdate`, `TrafficUpdate`, `MotionRequest`, and `StreamingUpdate`. +Further top-level messages that were added in later versions of OSI are `HostVehicleData`, `TrafficCommand`, `TrafficCommandUpdate`, `TrafficUpdate`, `MotionRequest`, and `StreamingUpdate`. The following figure shows the interfaces and models involved in modeling a sensor. diff --git a/osi3trace/osi_trace.py b/osi3trace/osi_trace.py index 1cc829bef..bc496fb69 100644 --- a/osi3trace/osi_trace.py +++ b/osi3trace/osi_trace.py @@ -7,6 +7,7 @@ from osi3.osi_sensorview_pb2 import SensorView from osi3.osi_groundtruth_pb2 import GroundTruth +from osi3.osi_hostvehicledata_pb2 import HostVehicleData from osi3.osi_sensordata_pb2 import SensorData from osi3.osi_sensorviewconfiguration_pb2 import SensorViewConfiguration from osi3.osi_trafficupdate_pb2 import TrafficUpdate @@ -19,6 +20,7 @@ MESSAGES_TYPE = { "SensorView": SensorView, "GroundTruth": GroundTruth, + "HostVehicleData": HostVehicleData, "SensorData": SensorData, "SensorViewConfiguration": SensorViewConfiguration, "TrafficUpdate": TrafficUpdate, diff --git a/tests/test_osi_trace.py b/tests/test_osi_trace.py index 09240277b..7c3845572 100644 --- a/tests/test_osi_trace.py +++ b/tests/test_osi_trace.py @@ -5,6 +5,7 @@ from osi3trace.osi_trace import OSITrace from osi3.osi_sensorview_pb2 import SensorView from osi3.osi_groundtruth_pb2 import GroundTruth +from osi3.osi_hostvehicledata_pb2 import HostVehicleData from osi3.osi_sensordata_pb2 import SensorData from osi3.osi_sensorviewconfiguration_pb2 import SensorViewConfiguration from osi3.osi_trafficupdate_pb2 import TrafficUpdate @@ -51,6 +52,23 @@ def test_osi_trace_gt(self): self.assertTrue(os.path.exists(path_output)) + def test_osi_trace_hvd(self): + with tempfile.TemporaryDirectory() as tmpdirname: + path_output = os.path.join(tmpdirname, "output_hvd.txth") + path_input = os.path.join(tmpdirname, "input_hvd.osi") + create_sample_hvd(path_input) + + trace = OSITrace(path_input, "HostVehicleData") + with open(path_output, "wt") as f: + for message in trace: + self.assertIsInstance(message, HostVehicleData) + f.write(str(message)) + + self.assertEqual(len(trace.retrieve_offsets()), 10) + trace.close() + + self.assertTrue(os.path.exists(path_output)) + def test_osi_trace_sd(self): with tempfile.TemporaryDirectory() as tmpdirname: path_output = os.path.join(tmpdirname, "output_sd.txth") @@ -280,6 +298,44 @@ def create_sample_gt(path): f.close() +def create_sample_hvd(path): + f = open(path, "ab") + hostvehicledata = HostVehicleData() + + hostvehicledata.version.version_major = 3 + hostvehicledata.version.version_minor = 0 + hostvehicledata.version.version_patch = 0 + + hostvehicledata.timestamp.seconds = 0 + hostvehicledata.timestamp.nanos = 0 + + hostvehicledata.host_vehicle_id.value = 114 + + # Generate 10 OSI messages for 9 seconds + for i in range(10): + # Increment the time + hostvehicledata.timestamp.seconds += 1 + hostvehicledata.timestamp.nanos += 100000 + + hostvehicledata.location.dimension.length = 5 + hostvehicledata.location.dimension.width = 2 + hostvehicledata.location.dimension.height = 1 + + hostvehicledata.location.position.x = 0.0 + i + hostvehicledata.location.position.y = 0.0 + hostvehicledata.location.position.z = 0.0 + + hostvehicledata.location.orientation.roll = 0.0 + hostvehicledata.location.orientation.pitch = 0.0 + hostvehicledata.location.orientation.yaw = 0.0 + + """Serialize""" + bytes_buffer = hostvehicledata.SerializeToString() + f.write(struct.pack(" Date: Mon, 10 Jun 2024 11:56:33 +0200 Subject: [PATCH 112/113] Add missing trace file prefix adjust to common order Fixes #816. Signed-off-by: Pierre R. Mai --- doc/architecture/trace_file_naming.adoc | 26 ++- osi3trace/osi_trace.py | 8 +- tests/test_osi_trace.py | 204 ++++++++++++------------ 3 files changed, 125 insertions(+), 113 deletions(-) diff --git a/doc/architecture/trace_file_naming.adoc b/doc/architecture/trace_file_naming.adoc index 2c4bf46da..1c73ed90c 100644 --- a/doc/architecture/trace_file_naming.adoc +++ b/doc/architecture/trace_file_naming.adoc @@ -14,23 +14,35 @@ The names of OSI trace files should have the following format: **Types** -`sd`:: -Trace file contains `SensorData` messages. - `sv`:: Trace file contains `SensorView` messages. +`svc`:: +Trace file contains `SensorViewConfiguration` messages. + `gt`:: Trace file contains `GroundTruth` messages. -`tu`:: -Trace file contains `TrafficUpdate` messages. +`hvd`:: +Trace file contains `HostVehicleData` messages. + +`sd`:: +Trace file contains `SensorData` messages. `tc`:: Trace file contains `TrafficCommand` messages. -`hvd`:: -Trace file contains `HostVehicleData` messages. +`tcu`:: +Trace file contains `TrafficCommandUpdate` messages. + +`tu`:: +Trace file contains `TrafficUpdate` messages. + +`mr`:: +Trace file contains `MotionRequest` messages. + +`su`:: +Trace file contains `StreamingUpdate` messages. **Example** diff --git a/osi3trace/osi_trace.py b/osi3trace/osi_trace.py index bc496fb69..3c0577023 100644 --- a/osi3trace/osi_trace.py +++ b/osi3trace/osi_trace.py @@ -6,26 +6,26 @@ import struct from osi3.osi_sensorview_pb2 import SensorView +from osi3.osi_sensorviewconfiguration_pb2 import SensorViewConfiguration from osi3.osi_groundtruth_pb2 import GroundTruth from osi3.osi_hostvehicledata_pb2 import HostVehicleData from osi3.osi_sensordata_pb2 import SensorData -from osi3.osi_sensorviewconfiguration_pb2 import SensorViewConfiguration -from osi3.osi_trafficupdate_pb2 import TrafficUpdate from osi3.osi_trafficcommand_pb2 import TrafficCommand from osi3.osi_trafficcommandupdate_pb2 import TrafficCommandUpdate +from osi3.osi_trafficupdate_pb2 import TrafficUpdate from osi3.osi_motionrequest_pb2 import MotionRequest from osi3.osi_streamingupdate_pb2 import StreamingUpdate MESSAGES_TYPE = { "SensorView": SensorView, + "SensorViewConfiguration": SensorViewConfiguration, "GroundTruth": GroundTruth, "HostVehicleData": HostVehicleData, "SensorData": SensorData, - "SensorViewConfiguration": SensorViewConfiguration, - "TrafficUpdate": TrafficUpdate, "TrafficCommand": TrafficCommand, "TrafficCommandUpdate": TrafficCommandUpdate, + "TrafficUpdate": TrafficUpdate, "MotionRequest": MotionRequest, "StreamingUpdate": StreamingUpdate, } diff --git a/tests/test_osi_trace.py b/tests/test_osi_trace.py index 7c3845572..9d74f5a9d 100644 --- a/tests/test_osi_trace.py +++ b/tests/test_osi_trace.py @@ -4,13 +4,13 @@ from osi3trace.osi_trace import OSITrace from osi3.osi_sensorview_pb2 import SensorView +from osi3.osi_sensorviewconfiguration_pb2 import SensorViewConfiguration from osi3.osi_groundtruth_pb2 import GroundTruth from osi3.osi_hostvehicledata_pb2 import HostVehicleData from osi3.osi_sensordata_pb2 import SensorData -from osi3.osi_sensorviewconfiguration_pb2 import SensorViewConfiguration -from osi3.osi_trafficupdate_pb2 import TrafficUpdate from osi3.osi_trafficcommand_pb2 import TrafficCommand from osi3.osi_trafficcommandupdate_pb2 import TrafficCommandUpdate +from osi3.osi_trafficupdate_pb2 import TrafficUpdate from osi3.osi_motionrequest_pb2 import MotionRequest from osi3.osi_streamingupdate_pb2 import StreamingUpdate @@ -35,6 +35,23 @@ def test_osi_trace_sv(self): self.assertTrue(os.path.exists(path_output)) + def test_osi_trace_svc(self): + with tempfile.TemporaryDirectory() as tmpdirname: + path_output = os.path.join(tmpdirname, "output_svc.txth") + path_input = os.path.join(tmpdirname, "input_svc.osi") + create_sample_svc(path_input) + + trace = OSITrace(path_input, "SensorViewConfiguration") + with open(path_output, "wt") as f: + for message in trace: + self.assertIsInstance(message, SensorViewConfiguration) + f.write(str(message)) + + self.assertEqual(len(trace.retrieve_offsets()), 1) + trace.close() + + self.assertTrue(os.path.exists(path_output)) + def test_osi_trace_gt(self): with tempfile.TemporaryDirectory() as tmpdirname: path_output = os.path.join(tmpdirname, "output_gt.txth") @@ -86,40 +103,6 @@ def test_osi_trace_sd(self): self.assertTrue(os.path.exists(path_output)) - def test_osi_trace_svc(self): - with tempfile.TemporaryDirectory() as tmpdirname: - path_output = os.path.join(tmpdirname, "output_svc.txth") - path_input = os.path.join(tmpdirname, "input_svc.osi") - create_sample_svc(path_input) - - trace = OSITrace(path_input, "SensorViewConfiguration") - with open(path_output, "wt") as f: - for message in trace: - self.assertIsInstance(message, SensorViewConfiguration) - f.write(str(message)) - - self.assertEqual(len(trace.retrieve_offsets()), 1) - trace.close() - - self.assertTrue(os.path.exists(path_output)) - - def test_osi_trace_tu(self): - with tempfile.TemporaryDirectory() as tmpdirname: - path_output = os.path.join(tmpdirname, "output_tu.txth") - path_input = os.path.join(tmpdirname, "input_tu.osi") - create_sample_tu(path_input) - - trace = OSITrace(path_input, "TrafficUpdate") - with open(path_output, "wt") as f: - for message in trace: - self.assertIsInstance(message, TrafficUpdate) - f.write(str(message)) - - self.assertEqual(len(trace.retrieve_offsets()), 10) - trace.close() - - self.assertTrue(os.path.exists(path_output)) - def test_osi_trace_tc(self): with tempfile.TemporaryDirectory() as tmpdirname: path_output = os.path.join(tmpdirname, "output_tc.txth") @@ -154,6 +137,23 @@ def test_osi_trace_tcu(self): self.assertTrue(os.path.exists(path_output)) + def test_osi_trace_tu(self): + with tempfile.TemporaryDirectory() as tmpdirname: + path_output = os.path.join(tmpdirname, "output_tu.txth") + path_input = os.path.join(tmpdirname, "input_tu.osi") + create_sample_tu(path_input) + + trace = OSITrace(path_input, "TrafficUpdate") + with open(path_output, "wt") as f: + for message in trace: + self.assertIsInstance(message, TrafficUpdate) + f.write(str(message)) + + self.assertEqual(len(trace.retrieve_offsets()), 10) + trace.close() + + self.assertTrue(os.path.exists(path_output)) + def test_osi_trace_mr(self): with tempfile.TemporaryDirectory() as tmpdirname: path_output = os.path.join(tmpdirname, "output_mr.txth") @@ -257,6 +257,31 @@ def create_sample_sv(path): f.close() +def create_sample_svc(path): + f = open(path, "ab") + sensorviewconfig = SensorViewConfiguration() + + sensorviewconfig.version.version_major = 3 + sensorviewconfig.version.version_minor = 0 + sensorviewconfig.version.version_patch = 0 + + sensorviewconfig.sensor_id.value = 42 + + sensorviewconfig.mounting_position.position.x = 0.8 + sensorviewconfig.mounting_position.position.y = 1.0 + sensorviewconfig.mounting_position.position.z = 0.5 + + sensorviewconfig.mounting_position.orientation.roll = 0.10 + sensorviewconfig.mounting_position.orientation.pitch = 0.15 + sensorviewconfig.mounting_position.orientation.yaw = 0.25 + + """Serialize""" + bytes_buffer = sensorviewconfig.SerializeToString() + f.write(struct.pack(" Date: Mon, 15 Jul 2024 13:26:16 +0200 Subject: [PATCH 113/113] Ensure only actual releases get published on PyPI Signed-off-by: Pierre R. Mai --- .github/workflows/protobuf.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/protobuf.yml b/.github/workflows/protobuf.yml index 0e15a3ed3..e0398dc6c 100644 --- a/.github/workflows/protobuf.yml +++ b/.github/workflows/protobuf.yml @@ -250,5 +250,5 @@ jobs: repository-url: https://test.pypi.org/legacy/ - name: Publish Full Release on PyPI - if: startsWith(github.ref, 'refs/tags/v') + if: startsWith(github.ref, 'refs/tags/v') && ( ! contains(github.ref, '-') ) uses: pypa/gh-action-pypi-publish@release/v1