Module vcd.poly2d

Module to handle representations fo 2D polygons.

This module implements functions to transform and handle poly2D elements.

Expand source code
"""
Module to handle representations fo 2D polygons.

This module implements functions to transform and handle poly2D elements.
"""
# VCD (Video Content Description) library.
#
# Project website: http://vcd.vicomtech.org
#
# Copyright (C) 2023, Vicomtech (http://www.vicomtech.es/),
# (Spain) all rights reserved.
#
# VCD is a Python library to create and manage OpenLABEL content.
# VCD is distributed under MIT License. See LICENSE.

from __future__ import annotations

import math

import numpy as np


def compute_rs6fcc(coords: tuple | list) -> tuple[list[int], int, int, int, int]:
    """
    Convert the polyline points using RS6FCC method.

    Args:
        coords (list): list of x, y coordinates of the polyline points.
    """
    _distances = []
    # high_symbol = 7
    # low_symbol = 6

    if len(coords) == 0:
        return [], 0, 0, 0, 0

    _xinit = int(coords[0])
    _yinit = int(coords[1])
    xinit = _xinit
    yinit = _yinit

    static_direction_kernel = np.array([[5, 6, 7], [4, 9, 0], [3, 2, 1]])

    kernel_direction_data = np.array(
        [
            [[5, 4, 2], [5, 9, 0], [5, 3, 1]],  # direction 0 updated kernel
            [[5, 5, 4], [5, 9, 2], [3, 1, 0]],  # direction 1 updated kernel
            [[5, 5, 5], [3, 9, 4], [1, 0, 2]],  # direction 2 updated kernel
            [[3, 5, 5], [1, 9, 5], [0, 2, 4]],  # direction 3 updated kernel
            [[1, 3, 5], [0, 9, 5], [2, 4, 5]],  # direction 4 updated kernel
            [[0, 1, 3], [2, 9, 5], [4, 5, 5]],  # direction 5 updated kernel
            [[2, 0, 1], [4, 9, 3], [5, 5, 5]],  # direction 6 updated kernel
            [[4, 2, 0], [5, 9, 1], [5, 5, 3]],
        ]
    )  # direction 7 updated kernel
    # the polygon contouring starts always going down.
    previous_direction = 2

    for i in range(2, len(coords), 2):
        x = round(coords[i])
        y = round(coords[i + 1])
        xi = x - xinit
        yi = y - yinit
        temp = []
        fin = max(abs(xi), abs(yi))

        xii = int(xi / abs(xi)) if xi != 0 else 0
        yii = int(yi / abs(yi)) if yi != 0 else 0

        for _j in range(0, fin):
            move = kernel_direction_data[previous_direction][yii + 1][xii + 1]
            if move < 5:
                temp.append(move)
                previous_direction = static_direction_kernel[yii + 1][xii + 1]
            elif move == 5:
                temp.append(move)
                previous_direction = (previous_direction + 4) % 8
                move = kernel_direction_data[previous_direction][yii + 1][xii + 1]
                temp.append(move)
                previous_direction = static_direction_kernel[yii + 1][xii + 1]

        for _, elem in enumerate(temp):
            _distances.append(elem)

        xinit = x
        yinit = y

    if len(_distances) != 0:
        (
            _distances,
            rs6fcc_low_simplifier,
            rs6fcc_high_simplifier,
        ) = simplify_calculated_front_sequence_movements(_distances)
    else:
        rs6fcc_high_simplifier = 0
        rs6fcc_low_simplifier = 0

    return _distances, rs6fcc_low_simplifier, rs6fcc_high_simplifier, _xinit, _yinit


def extract_rs6fcc2points(
    _chaincode: list[int], _xinit: int, _yinit: int, _low: int, _high: int
) -> list[int]:
    rs6fcc_high_simplifier = _high
    rs6fcc_low_simplifier = _low
    rs6fcc_high_symbol = 7
    rs6fcc_low_symbol = 6
    _coords = []
    _coords.append(int(_xinit))
    _coords.append(int(_yinit))
    xinit = int(_xinit)
    yinit = int(_yinit)
    if len(_chaincode) == 0:
        return _coords

    static_direction_kernel = np.array([[5, 6, 7], [4, 9, 0], [3, 2, 1]])

    kernel_direction_data = np.array(
        [
            [[5, 4, 2], [5, 9, 0], [5, 3, 1]],  # direction 0 updated kernel
            [[5, 5, 4], [5, 9, 2], [3, 1, 0]],  # direction 1 updated kernel
            [[5, 5, 5], [3, 9, 4], [1, 0, 2]],  # direction 2 updated kernel
            [[3, 5, 5], [1, 9, 5], [0, 2, 4]],  # direction 3 updated kernel
            [[1, 3, 5], [0, 9, 5], [2, 4, 5]],  # direction 4 updated kernel
            [[0, 1, 3], [2, 9, 5], [4, 5, 5]],  # direction 5 updated kernel
            [[2, 0, 1], [4, 9, 3], [5, 5, 5]],  # direction 6 updated kernel
            [[4, 2, 0], [5, 9, 1], [5, 5, 3]],
        ]
    )  # direction 7 updated kernel
    # the polygon contouring starts always going down.
    previous_direction = 2

    counter = 0
    for i, code in enumerate(_chaincode):
        if 6 > code > 0:
            if counter > 0:
                x, y = check_pixel_in_mat(kernel_direction_data[previous_direction], 0)
                xinit += x * counter if x != 0 else 0
                yinit += y * counter if y != 0 else 0
                _coords.append(xinit)
                _coords.append(yinit)
                counter = 0

            if code == 5:
                previous_direction = (previous_direction + 4) % 8
            else:
                xi, yi = check_pixel_in_mat(
                    kernel_direction_data[previous_direction], code
                )
                xinit += xi
                yinit += yi
                _coords.append(xinit)
                _coords.append(yinit)
                previous_direction = static_direction_kernel[yi + 1][xi + 1]

        elif code == 0:
            counter += 1
        elif code == rs6fcc_low_symbol:
            counter += rs6fcc_low_simplifier
        elif code == rs6fcc_high_symbol:
            counter += rs6fcc_high_simplifier

        if i == len(_chaincode) - 1 and counter > 0:
            x, y = check_pixel_in_mat(kernel_direction_data[previous_direction], 0)
            xinit += x * counter if x != 0 else 0
            yinit += y * counter if y != 0 else 0
            _coords.append(xinit)
            _coords.append(yinit)

    return _coords


def compute_srf6dcc(_coords: tuple | list) -> tuple[list[int], int, int]:
    _distances = []
    srf6dcc_high_simplifier = 15
    srf6dcc_low_simplifier = 3
    srf6dcc_high_symbol = 7
    srf6dcc_low_symbol = 6
    if len(_coords) == 0:
        return [], 0, 0
    _xinit = int(_coords[0])
    _yinit = int(_coords[1])
    xinit = _xinit
    yinit = _yinit

    static_direction_kernel = np.array([[5, 6, 7], [4, 9, 0], [3, 2, 1]])

    kernel_direction_data = np.array(
        [
            [[5, 4, 2], [5, 9, 0], [5, 3, 1]],  # direction 0 updated kernel
            [[5, 5, 4], [5, 9, 2], [3, 1, 0]],  # direction 1 updated kernel
            [[5, 5, 5], [3, 9, 4], [1, 0, 2]],  # direction 2 updated kernel
            [[3, 5, 5], [1, 9, 5], [0, 2, 4]],  # direction 3 updated kernel
            [[1, 3, 5], [0, 9, 5], [2, 4, 5]],  # direction 4 updated kernel
            [[0, 1, 3], [2, 9, 5], [4, 5, 5]],  # direction 5 updated kernel
            [[2, 0, 1], [4, 9, 3], [5, 5, 5]],  # direction 6 updated kernel
            [[4, 2, 0], [5, 9, 1], [5, 5, 3]],
        ]
    )  # direction 7 updated kernel
    # the polygon contouring starts always going down.
    # the polygon contouring starts always going down.
    previous_direction = 2
    for i in range(2, len(_coords), 2):
        x = round(_coords[i])
        y = round(_coords[i + 1])
        xi = x - xinit
        yi = y - yinit
        temp = []
        fin = max(abs(xi), abs(yi))

        xii = int(xi / abs(xi)) if xi != 0 else 0
        yii = int(yi / abs(yi)) if yi != 0 else 0

        for _j in range(0, fin):
            move = kernel_direction_data[previous_direction][yii + 1][xii + 1]
            if move < 5:
                temp.append(move)
                previous_direction = static_direction_kernel[yii + 1][xii + 1]
            elif move == 5:
                temp.append(move)
                previous_direction = (previous_direction + 4) % 8
                move = kernel_direction_data[previous_direction][yii + 1][xii + 1]
                temp.append(move)
                previous_direction = static_direction_kernel[yii + 1][xii + 1]

        for _, elem in enumerate(temp):
            _distances.append(elem)

        xinit = x
        yinit = y

        if len(_distances) != 0:
            _distances = simplify_all_front_sequence_movements(
                _distances,
                srf6dcc_low_simplifier,
                srf6dcc_high_simplifier,
                srf6dcc_low_symbol,
                srf6dcc_high_symbol,
            )
    return _distances, _xinit, _yinit


def extract_srf6dcc2points(_chaincode: list[int], _xinit: int, _yinit: int) -> list[int]:
    srf6dcc_high_simplifier = 15
    srf6dcc_low_simplifier = 3
    return extract_rs6fcc2points(
        _chaincode, _xinit, _yinit, srf6dcc_low_simplifier, srf6dcc_high_simplifier
    )


def check_pixel_in_mat(
    _kernel_direction_data: list[list[int]], target: int
) -> tuple[int, int]:
    for row in range(0, 3):
        for col in range(0, 3):
            if _kernel_direction_data[row][col] == target:
                return col - 1, row - 1
    return 0, 0


def check_value_in_kernel(
    _kernel_direction_data: list[list[int]], target: int
) -> tuple[int, int]:
    for row in range(0, 3):
        for col in range(0, 3):
            if _kernel_direction_data[row][col] == target:
                return col, row
    return 0, 0


def simplify_front_sequence_movements(
    _num: int,
    _low: int,
    _high: int,
    _low_symbol: int,
    _high_symbol: int,
    _next_steps: list[int],
) -> list[int]:
    if _high != -1:
        res1 = int(math.floor(_num / _high))
        res2 = int(_num % _high / _low)
        res3 = int(_num % _high % _low)
    else:
        res1 = 0
        res2 = int(_num / _low)
        res3 = int(_num % _low)

    for _i in range(0, res1):
        # _high_symbol: {SRF6DCC: 7} for high Roman numerals-like counting simplifications
        _next_steps.append(_high_symbol)
    for _i in range(0, res2):
        # _low_symbol: {SRF6DCC: 6} for low Roman numerals-like counting simplifications
        _next_steps.append(_low_symbol)
    for _i in range(0, res3):
        _next_steps.append(0)
    return _next_steps


def simplify_all_front_sequence_movements(
    _chaincode: list[int], _low: int, _high: int, _low_symbol: int, _high_symbol: int
) -> list[int]:
    counter = 0
    i = 0
    while i < len(_chaincode):
        if _chaincode[i] == 0:
            counter += 1
        elif _chaincode[i] != 0:
            if counter >= _low:
                # i - counter //position of last 0 - counter
                next_steps: list[int] = []
                next_steps = simplify_front_sequence_movements(
                    counter, _low, _high, _low_symbol, _high_symbol, next_steps
                )
                del _chaincode[i - counter : i]
                i -= counter
                _chaincode[i:i] = next_steps
                i += len(next_steps)
            counter = 0
        if i == len(_chaincode) - 1:
            if counter >= _low:
                next_steps = []
                next_steps = simplify_front_sequence_movements(
                    counter, _low, _high, _low_symbol, _high_symbol, next_steps
                )
                del _chaincode[len(_chaincode) - counter : len(_chaincode)]
                i -= counter
                _chaincode[len(_chaincode) : len(_chaincode)] = next_steps
                i += len(next_steps)
            counter = 0
        i += 1
    return _chaincode


def base64_encoder(_num: int) -> str:
    alphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"
    return alphabet[_num]


def base64_decoder(_value: str) -> int:
    alphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"
    return alphabet.find(_value)


# Converts a vector of chaincode integers into a json printable characters string.
# By joining the digits to compose a 6 bits integer and the converting that integer in
# base64 character.
def chaincode_base64_encoder(
    _chaincodevector: list[int], _chaincode_bits: int
) -> tuple[str, int]:
    # Add odd number in the vector for codification
    num_digits = int(6 / _chaincode_bits)
    _outputstring = ""
    rest = len(_chaincodevector) % num_digits
    if rest != 0:
        vectrest = int(num_digits - rest)
        for _i in range(0, vectrest):
            _chaincodevector.append(0)
    else:
        vectrest = 0
    for i in range(0, len(_chaincodevector), num_digits):
        byte = 0
        for j in range(0, num_digits):
            byte += _chaincodevector[i + j] << (num_digits - 1 - j) * _chaincode_bits
        _outputstring += base64_encoder(byte)
    return _outputstring, vectrest


# Converts back the json printable characters string to a vector of chaincode integers.
# By converting from base64 to 6bits integer and then splitting in chain code vector.
def chaincode_base64_decoder(
    _chaincodebits: str, _chaincode_bits: int, _bitsvectorrest: int
) -> list[int]:
    _chaincodevector: list[int] = []
    num_digits = int(6 / _chaincode_bits)
    getbits = pow(2, _chaincode_bits) - 1  # number of bits that need to move to

    for i, chaincode in enumerate(_chaincodebits):
        byte = base64_decoder(chaincode)
        for _j in range(0, num_digits):
            number = byte & getbits
            _chaincodevector.insert(i * num_digits, number)
            byte -= number
            byte = byte >> _chaincode_bits

    for _k in range(0, _bitsvectorrest):
        _chaincodevector.pop(len(_chaincodevector) - 1)

    return _chaincodevector


def calculate_multiplier(val: float, x: float) -> int:
    return int(math.floor(val / x) + (val % x))


def calculate_multiplier2(val: float, x: float, y: float) -> int:
    return calculate_multiplier(math.floor(val / y) + (val % y), x)


def extract_multiplier_map(in_map: dict) -> int:
    min_repetition = 0
    min_suma = math.inf
    for key_i in in_map:
        suma = 0
        for key_j in in_map:
            suma += in_map[key_j] * calculate_multiplier(key_j, key_i)
        if suma < min_suma:
            min_repetition = key_i
            min_suma = suma
    return min_repetition


def extract_multiplier_map2(in_map: dict) -> tuple[int, int]:
    min_suma = math.inf
    map_items = list(in_map.items())
    for val_i in map_items[:-1]:
        for val_j in map_items[1:]:
            suma = 0
            for val_k in map_items:
                suma += val_k[1] * calculate_multiplier2(val_k[0], val_i[0], val_j[0])
            if suma < min_suma:
                min_repetition_1 = val_i[0]
                min_repetition_2 = val_j[0]
                min_suma = suma
    return min_repetition_1, min_repetition_2


def simplify_calculated_front_sequence_movements(
    _chaincode: list[int],
) -> tuple[list[int], int, int]:
    repetition_counter_map: dict = {}
    i = 0
    while i < len(_chaincode) - 1:
        if _chaincode[i] == 0:
            counter = 1
            j = i + 1
            while j < len(_chaincode):
                if _chaincode[j] == 0:
                    counter += 1
                    if j == len(_chaincode) - 1:
                        i = j - 1
                else:
                    i = j - 1
                    break
                j = j + 1
            if counter > 1:
                if repetition_counter_map.get(counter) is None:
                    repetition_counter_map[counter] = 1
                else:
                    repetition_counter_map[counter] += 1
        i += 1

    if len(repetition_counter_map) <= 0:
        _low = -1
        _high = -1

    elif len(repetition_counter_map) == 1:
        for key in repetition_counter_map:
            _low = key
        _high = -1
        _chaincode = simplify_all_front_sequence_movements(_chaincode, _low, _high, 6, 7)
    elif len(repetition_counter_map) == 2:
        count = 0
        for key in repetition_counter_map:
            if count == 0:
                _low = key
            else:
                _high = key
            count += 1
        _chaincode = simplify_all_front_sequence_movements(_chaincode, _low, _high, 6, 7)
    else:
        _low, _high = extract_multiplier_map2(repetition_counter_map)
        _chaincode = simplify_all_front_sequence_movements(_chaincode, _low, _high, 6, 7)

    return _chaincode, _low, _high


def get_vec_from_encoded_srf6(x: int, y: int, rest: int, encoded_poly: str) -> list[int]:
    decoded = chaincode_base64_decoder(encoded_poly, 3, rest)
    vec = extract_srf6dcc2points(decoded, x, y)
    return vec


def get_vec_from_encoded_rs6(
    x: int, y: int, low: int, high: int, rest: int, encoded_poly: str
) -> list[int]:
    decoded = chaincode_base64_decoder(encoded_poly, 3, rest)
    vec = extract_rs6fcc2points(decoded, x, y, low, high)
    return vec

Functions

def base64_decoder(_value: str) ‑> int
Expand source code
def base64_decoder(_value: str) -> int:
    alphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"
    return alphabet.find(_value)
def base64_encoder(_num: int) ‑> str
Expand source code
def base64_encoder(_num: int) -> str:
    alphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"
    return alphabet[_num]
def calculate_multiplier(val: float, x: float) ‑> int
Expand source code
def calculate_multiplier(val: float, x: float) -> int:
    return int(math.floor(val / x) + (val % x))
def calculate_multiplier2(val: float, x: float, y: float) ‑> int
Expand source code
def calculate_multiplier2(val: float, x: float, y: float) -> int:
    return calculate_multiplier(math.floor(val / y) + (val % y), x)
def chaincode_base64_decoder(_chaincodebits: str, _chaincode_bits: int, _bitsvectorrest: int) ‑> list[int]
Expand source code
def chaincode_base64_decoder(
    _chaincodebits: str, _chaincode_bits: int, _bitsvectorrest: int
) -> list[int]:
    _chaincodevector: list[int] = []
    num_digits = int(6 / _chaincode_bits)
    getbits = pow(2, _chaincode_bits) - 1  # number of bits that need to move to

    for i, chaincode in enumerate(_chaincodebits):
        byte = base64_decoder(chaincode)
        for _j in range(0, num_digits):
            number = byte & getbits
            _chaincodevector.insert(i * num_digits, number)
            byte -= number
            byte = byte >> _chaincode_bits

    for _k in range(0, _bitsvectorrest):
        _chaincodevector.pop(len(_chaincodevector) - 1)

    return _chaincodevector
def chaincode_base64_encoder(_chaincodevector: list[int], _chaincode_bits: int) ‑> tuple[str, int]
Expand source code
def chaincode_base64_encoder(
    _chaincodevector: list[int], _chaincode_bits: int
) -> tuple[str, int]:
    # Add odd number in the vector for codification
    num_digits = int(6 / _chaincode_bits)
    _outputstring = ""
    rest = len(_chaincodevector) % num_digits
    if rest != 0:
        vectrest = int(num_digits - rest)
        for _i in range(0, vectrest):
            _chaincodevector.append(0)
    else:
        vectrest = 0
    for i in range(0, len(_chaincodevector), num_digits):
        byte = 0
        for j in range(0, num_digits):
            byte += _chaincodevector[i + j] << (num_digits - 1 - j) * _chaincode_bits
        _outputstring += base64_encoder(byte)
    return _outputstring, vectrest
def check_pixel_in_mat(_kernel_direction_data: list[list[int]], target: int) ‑> tuple[int, int]
Expand source code
def check_pixel_in_mat(
    _kernel_direction_data: list[list[int]], target: int
) -> tuple[int, int]:
    for row in range(0, 3):
        for col in range(0, 3):
            if _kernel_direction_data[row][col] == target:
                return col - 1, row - 1
    return 0, 0
def check_value_in_kernel(_kernel_direction_data: list[list[int]], target: int) ‑> tuple[int, int]
Expand source code
def check_value_in_kernel(
    _kernel_direction_data: list[list[int]], target: int
) -> tuple[int, int]:
    for row in range(0, 3):
        for col in range(0, 3):
            if _kernel_direction_data[row][col] == target:
                return col, row
    return 0, 0
def compute_rs6fcc(coords: tuple | list) ‑> tuple[list[int], int, int, int, int]

Convert the polyline points using RS6FCC method.

Args

coords : list
list of x, y coordinates of the polyline points.
Expand source code
def compute_rs6fcc(coords: tuple | list) -> tuple[list[int], int, int, int, int]:
    """
    Convert the polyline points using RS6FCC method.

    Args:
        coords (list): list of x, y coordinates of the polyline points.
    """
    _distances = []
    # high_symbol = 7
    # low_symbol = 6

    if len(coords) == 0:
        return [], 0, 0, 0, 0

    _xinit = int(coords[0])
    _yinit = int(coords[1])
    xinit = _xinit
    yinit = _yinit

    static_direction_kernel = np.array([[5, 6, 7], [4, 9, 0], [3, 2, 1]])

    kernel_direction_data = np.array(
        [
            [[5, 4, 2], [5, 9, 0], [5, 3, 1]],  # direction 0 updated kernel
            [[5, 5, 4], [5, 9, 2], [3, 1, 0]],  # direction 1 updated kernel
            [[5, 5, 5], [3, 9, 4], [1, 0, 2]],  # direction 2 updated kernel
            [[3, 5, 5], [1, 9, 5], [0, 2, 4]],  # direction 3 updated kernel
            [[1, 3, 5], [0, 9, 5], [2, 4, 5]],  # direction 4 updated kernel
            [[0, 1, 3], [2, 9, 5], [4, 5, 5]],  # direction 5 updated kernel
            [[2, 0, 1], [4, 9, 3], [5, 5, 5]],  # direction 6 updated kernel
            [[4, 2, 0], [5, 9, 1], [5, 5, 3]],
        ]
    )  # direction 7 updated kernel
    # the polygon contouring starts always going down.
    previous_direction = 2

    for i in range(2, len(coords), 2):
        x = round(coords[i])
        y = round(coords[i + 1])
        xi = x - xinit
        yi = y - yinit
        temp = []
        fin = max(abs(xi), abs(yi))

        xii = int(xi / abs(xi)) if xi != 0 else 0
        yii = int(yi / abs(yi)) if yi != 0 else 0

        for _j in range(0, fin):
            move = kernel_direction_data[previous_direction][yii + 1][xii + 1]
            if move < 5:
                temp.append(move)
                previous_direction = static_direction_kernel[yii + 1][xii + 1]
            elif move == 5:
                temp.append(move)
                previous_direction = (previous_direction + 4) % 8
                move = kernel_direction_data[previous_direction][yii + 1][xii + 1]
                temp.append(move)
                previous_direction = static_direction_kernel[yii + 1][xii + 1]

        for _, elem in enumerate(temp):
            _distances.append(elem)

        xinit = x
        yinit = y

    if len(_distances) != 0:
        (
            _distances,
            rs6fcc_low_simplifier,
            rs6fcc_high_simplifier,
        ) = simplify_calculated_front_sequence_movements(_distances)
    else:
        rs6fcc_high_simplifier = 0
        rs6fcc_low_simplifier = 0

    return _distances, rs6fcc_low_simplifier, rs6fcc_high_simplifier, _xinit, _yinit
def compute_srf6dcc(_coords: tuple | list) ‑> tuple[list[int], int, int]
Expand source code
def compute_srf6dcc(_coords: tuple | list) -> tuple[list[int], int, int]:
    _distances = []
    srf6dcc_high_simplifier = 15
    srf6dcc_low_simplifier = 3
    srf6dcc_high_symbol = 7
    srf6dcc_low_symbol = 6
    if len(_coords) == 0:
        return [], 0, 0
    _xinit = int(_coords[0])
    _yinit = int(_coords[1])
    xinit = _xinit
    yinit = _yinit

    static_direction_kernel = np.array([[5, 6, 7], [4, 9, 0], [3, 2, 1]])

    kernel_direction_data = np.array(
        [
            [[5, 4, 2], [5, 9, 0], [5, 3, 1]],  # direction 0 updated kernel
            [[5, 5, 4], [5, 9, 2], [3, 1, 0]],  # direction 1 updated kernel
            [[5, 5, 5], [3, 9, 4], [1, 0, 2]],  # direction 2 updated kernel
            [[3, 5, 5], [1, 9, 5], [0, 2, 4]],  # direction 3 updated kernel
            [[1, 3, 5], [0, 9, 5], [2, 4, 5]],  # direction 4 updated kernel
            [[0, 1, 3], [2, 9, 5], [4, 5, 5]],  # direction 5 updated kernel
            [[2, 0, 1], [4, 9, 3], [5, 5, 5]],  # direction 6 updated kernel
            [[4, 2, 0], [5, 9, 1], [5, 5, 3]],
        ]
    )  # direction 7 updated kernel
    # the polygon contouring starts always going down.
    # the polygon contouring starts always going down.
    previous_direction = 2
    for i in range(2, len(_coords), 2):
        x = round(_coords[i])
        y = round(_coords[i + 1])
        xi = x - xinit
        yi = y - yinit
        temp = []
        fin = max(abs(xi), abs(yi))

        xii = int(xi / abs(xi)) if xi != 0 else 0
        yii = int(yi / abs(yi)) if yi != 0 else 0

        for _j in range(0, fin):
            move = kernel_direction_data[previous_direction][yii + 1][xii + 1]
            if move < 5:
                temp.append(move)
                previous_direction = static_direction_kernel[yii + 1][xii + 1]
            elif move == 5:
                temp.append(move)
                previous_direction = (previous_direction + 4) % 8
                move = kernel_direction_data[previous_direction][yii + 1][xii + 1]
                temp.append(move)
                previous_direction = static_direction_kernel[yii + 1][xii + 1]

        for _, elem in enumerate(temp):
            _distances.append(elem)

        xinit = x
        yinit = y

        if len(_distances) != 0:
            _distances = simplify_all_front_sequence_movements(
                _distances,
                srf6dcc_low_simplifier,
                srf6dcc_high_simplifier,
                srf6dcc_low_symbol,
                srf6dcc_high_symbol,
            )
    return _distances, _xinit, _yinit
def extract_multiplier_map(in_map: dict) ‑> int
Expand source code
def extract_multiplier_map(in_map: dict) -> int:
    min_repetition = 0
    min_suma = math.inf
    for key_i in in_map:
        suma = 0
        for key_j in in_map:
            suma += in_map[key_j] * calculate_multiplier(key_j, key_i)
        if suma < min_suma:
            min_repetition = key_i
            min_suma = suma
    return min_repetition
def extract_multiplier_map2(in_map: dict) ‑> tuple[int, int]
Expand source code
def extract_multiplier_map2(in_map: dict) -> tuple[int, int]:
    min_suma = math.inf
    map_items = list(in_map.items())
    for val_i in map_items[:-1]:
        for val_j in map_items[1:]:
            suma = 0
            for val_k in map_items:
                suma += val_k[1] * calculate_multiplier2(val_k[0], val_i[0], val_j[0])
            if suma < min_suma:
                min_repetition_1 = val_i[0]
                min_repetition_2 = val_j[0]
                min_suma = suma
    return min_repetition_1, min_repetition_2
def extract_rs6fcc2points(_chaincode: list[int], _xinit: int, _yinit: int, _low: int, _high: int) ‑> list[int]
Expand source code
def extract_rs6fcc2points(
    _chaincode: list[int], _xinit: int, _yinit: int, _low: int, _high: int
) -> list[int]:
    rs6fcc_high_simplifier = _high
    rs6fcc_low_simplifier = _low
    rs6fcc_high_symbol = 7
    rs6fcc_low_symbol = 6
    _coords = []
    _coords.append(int(_xinit))
    _coords.append(int(_yinit))
    xinit = int(_xinit)
    yinit = int(_yinit)
    if len(_chaincode) == 0:
        return _coords

    static_direction_kernel = np.array([[5, 6, 7], [4, 9, 0], [3, 2, 1]])

    kernel_direction_data = np.array(
        [
            [[5, 4, 2], [5, 9, 0], [5, 3, 1]],  # direction 0 updated kernel
            [[5, 5, 4], [5, 9, 2], [3, 1, 0]],  # direction 1 updated kernel
            [[5, 5, 5], [3, 9, 4], [1, 0, 2]],  # direction 2 updated kernel
            [[3, 5, 5], [1, 9, 5], [0, 2, 4]],  # direction 3 updated kernel
            [[1, 3, 5], [0, 9, 5], [2, 4, 5]],  # direction 4 updated kernel
            [[0, 1, 3], [2, 9, 5], [4, 5, 5]],  # direction 5 updated kernel
            [[2, 0, 1], [4, 9, 3], [5, 5, 5]],  # direction 6 updated kernel
            [[4, 2, 0], [5, 9, 1], [5, 5, 3]],
        ]
    )  # direction 7 updated kernel
    # the polygon contouring starts always going down.
    previous_direction = 2

    counter = 0
    for i, code in enumerate(_chaincode):
        if 6 > code > 0:
            if counter > 0:
                x, y = check_pixel_in_mat(kernel_direction_data[previous_direction], 0)
                xinit += x * counter if x != 0 else 0
                yinit += y * counter if y != 0 else 0
                _coords.append(xinit)
                _coords.append(yinit)
                counter = 0

            if code == 5:
                previous_direction = (previous_direction + 4) % 8
            else:
                xi, yi = check_pixel_in_mat(
                    kernel_direction_data[previous_direction], code
                )
                xinit += xi
                yinit += yi
                _coords.append(xinit)
                _coords.append(yinit)
                previous_direction = static_direction_kernel[yi + 1][xi + 1]

        elif code == 0:
            counter += 1
        elif code == rs6fcc_low_symbol:
            counter += rs6fcc_low_simplifier
        elif code == rs6fcc_high_symbol:
            counter += rs6fcc_high_simplifier

        if i == len(_chaincode) - 1 and counter > 0:
            x, y = check_pixel_in_mat(kernel_direction_data[previous_direction], 0)
            xinit += x * counter if x != 0 else 0
            yinit += y * counter if y != 0 else 0
            _coords.append(xinit)
            _coords.append(yinit)

    return _coords
def extract_srf6dcc2points(_chaincode: list[int], _xinit: int, _yinit: int) ‑> list[int]
Expand source code
def extract_srf6dcc2points(_chaincode: list[int], _xinit: int, _yinit: int) -> list[int]:
    srf6dcc_high_simplifier = 15
    srf6dcc_low_simplifier = 3
    return extract_rs6fcc2points(
        _chaincode, _xinit, _yinit, srf6dcc_low_simplifier, srf6dcc_high_simplifier
    )
def get_vec_from_encoded_rs6(x: int, y: int, low: int, high: int, rest: int, encoded_poly: str) ‑> list[int]
Expand source code
def get_vec_from_encoded_rs6(
    x: int, y: int, low: int, high: int, rest: int, encoded_poly: str
) -> list[int]:
    decoded = chaincode_base64_decoder(encoded_poly, 3, rest)
    vec = extract_rs6fcc2points(decoded, x, y, low, high)
    return vec
def get_vec_from_encoded_srf6(x: int, y: int, rest: int, encoded_poly: str) ‑> list[int]
Expand source code
def get_vec_from_encoded_srf6(x: int, y: int, rest: int, encoded_poly: str) -> list[int]:
    decoded = chaincode_base64_decoder(encoded_poly, 3, rest)
    vec = extract_srf6dcc2points(decoded, x, y)
    return vec
def simplify_all_front_sequence_movements(_chaincode: list[int], _low: int, _high: int, _low_symbol: int, _high_symbol: int) ‑> list[int]
Expand source code
def simplify_all_front_sequence_movements(
    _chaincode: list[int], _low: int, _high: int, _low_symbol: int, _high_symbol: int
) -> list[int]:
    counter = 0
    i = 0
    while i < len(_chaincode):
        if _chaincode[i] == 0:
            counter += 1
        elif _chaincode[i] != 0:
            if counter >= _low:
                # i - counter //position of last 0 - counter
                next_steps: list[int] = []
                next_steps = simplify_front_sequence_movements(
                    counter, _low, _high, _low_symbol, _high_symbol, next_steps
                )
                del _chaincode[i - counter : i]
                i -= counter
                _chaincode[i:i] = next_steps
                i += len(next_steps)
            counter = 0
        if i == len(_chaincode) - 1:
            if counter >= _low:
                next_steps = []
                next_steps = simplify_front_sequence_movements(
                    counter, _low, _high, _low_symbol, _high_symbol, next_steps
                )
                del _chaincode[len(_chaincode) - counter : len(_chaincode)]
                i -= counter
                _chaincode[len(_chaincode) : len(_chaincode)] = next_steps
                i += len(next_steps)
            counter = 0
        i += 1
    return _chaincode
def simplify_calculated_front_sequence_movements(_chaincode: list[int]) ‑> tuple[list[int], int, int]
Expand source code
def simplify_calculated_front_sequence_movements(
    _chaincode: list[int],
) -> tuple[list[int], int, int]:
    repetition_counter_map: dict = {}
    i = 0
    while i < len(_chaincode) - 1:
        if _chaincode[i] == 0:
            counter = 1
            j = i + 1
            while j < len(_chaincode):
                if _chaincode[j] == 0:
                    counter += 1
                    if j == len(_chaincode) - 1:
                        i = j - 1
                else:
                    i = j - 1
                    break
                j = j + 1
            if counter > 1:
                if repetition_counter_map.get(counter) is None:
                    repetition_counter_map[counter] = 1
                else:
                    repetition_counter_map[counter] += 1
        i += 1

    if len(repetition_counter_map) <= 0:
        _low = -1
        _high = -1

    elif len(repetition_counter_map) == 1:
        for key in repetition_counter_map:
            _low = key
        _high = -1
        _chaincode = simplify_all_front_sequence_movements(_chaincode, _low, _high, 6, 7)
    elif len(repetition_counter_map) == 2:
        count = 0
        for key in repetition_counter_map:
            if count == 0:
                _low = key
            else:
                _high = key
            count += 1
        _chaincode = simplify_all_front_sequence_movements(_chaincode, _low, _high, 6, 7)
    else:
        _low, _high = extract_multiplier_map2(repetition_counter_map)
        _chaincode = simplify_all_front_sequence_movements(_chaincode, _low, _high, 6, 7)

    return _chaincode, _low, _high
def simplify_front_sequence_movements(_num: int, _low: int, _high: int, _low_symbol: int, _high_symbol: int, _next_steps: list[int]) ‑> list[int]
Expand source code
def simplify_front_sequence_movements(
    _num: int,
    _low: int,
    _high: int,
    _low_symbol: int,
    _high_symbol: int,
    _next_steps: list[int],
) -> list[int]:
    if _high != -1:
        res1 = int(math.floor(_num / _high))
        res2 = int(_num % _high / _low)
        res3 = int(_num % _high % _low)
    else:
        res1 = 0
        res2 = int(_num / _low)
        res3 = int(_num % _low)

    for _i in range(0, res1):
        # _high_symbol: {SRF6DCC: 7} for high Roman numerals-like counting simplifications
        _next_steps.append(_high_symbol)
    for _i in range(0, res2):
        # _low_symbol: {SRF6DCC: 6} for low Roman numerals-like counting simplifications
        _next_steps.append(_low_symbol)
    for _i in range(0, res3):
        _next_steps.append(0)
    return _next_steps