Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
27 changes: 27 additions & 0 deletions mapillary_tools/constants.py
Original file line number Diff line number Diff line change
Expand Up @@ -137,6 +137,33 @@ def _parse_scaled_integers(
os.getenv(_ENV_PREFIX + "MAX_SEQUENCE_PIXELS", "6G")
)

# Max amount of `MAPAltitude` value decimal digit positions written to image description file
ALTITUDE_BASE10_DIGIT_PLACES_PRECISION: int = int(
os.getenv(_ENV_PREFIX + "ALTITUDE_PRECISION_BASE10_DIGITS", 10)
)
# http://wiki.gis.com/wiki/index.php/Decimal_degrees
# decimal places degrees distance
# 0 1.0 111 km
# 1 0.1 11.1 km
# 2 0.01 1.11 km
# 3 0.001 111 m
# 4 0.0001 11.1 m
# 5 0.00001 1.11 m
# 6 0.000001 0.111 m
# 7 0.0000001 1.11 cm
# 8 0.00000001 1.11 mm
# Max amount of `MAPLatitude` and `MAPLongitude` value decimal digit positions
# written to image description file
COORDINATE_BASE10_DIGIT_PLACES_PRECISION: int = int(
os.getenv(_ENV_PREFIX + "COORDINATES_PRECISION_BASE10_DIGITS", 10)
)
# Max amount of `MAPCompassHeading` value decimal digit positions written to
# image description file
DIRECTION_BASE10_DIGIT_PLACES_PRECISION: int = int(
os.getenv(_ENV_PREFIX + "DIRECTION_PRECISION_BASE10_DIGITS", 10)
)
# Smallest time delta in seconds (must not be user customized due to `datetime`’s fixed ε)
_TIME_EPSILON: float = 1e-6

##################
##### UPLOAD #####
Expand Down
90 changes: 65 additions & 25 deletions mapillary_tools/serializer/description.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
import dataclasses
import datetime
import json
import math
import sys
import typing as T
from pathlib import Path
Expand All @@ -21,6 +22,11 @@
import jsonschema

from .. import exceptions, geo
from ..constants import (
ALTITUDE_BASE10_DIGIT_PLACES_PRECISION,
COORDINATE_BASE10_DIGIT_PLACES_PRECISION,
DIRECTION_BASE10_DIGIT_PLACES_PRECISION,
)
from ..types import (
BaseSerializer,
describe_error_metadata,
Expand All @@ -33,22 +39,6 @@
)


# http://wiki.gis.com/wiki/index.php/Decimal_degrees
# decimal places degrees distance
# 0 1.0 111 km
# 1 0.1 11.1 km
# 2 0.01 1.11 km
# 3 0.001 111 m
# 4 0.0001 11.1 m
# 5 0.00001 1.11 m
# 6 0.000001 0.111 m
# 7 0.0000001 1.11 cm
# 8 0.00000001 1.11 mm
_COORDINATES_PRECISION = 7
_ALTITUDE_PRECISION = 3
_ANGLE_PRECISION = 3


class _CompassHeading(TypedDict, total=True):
TrueHeading: float
MagneticHeading: float
Expand Down Expand Up @@ -209,6 +199,13 @@ class ErrorDescription(TypedDict, total=False):
}


def _fraction_decimal_digits(value: float, precision: int) -> int:
fraction_digits: int = precision - math.ceil(
math.log10(value if (value := int(math.fabs(value))) > 0 else 1)
)
return fraction_digits if fraction_digits >= 0 else 0


def _merge_schema(*schemas: dict) -> dict:
for s in schemas:
assert s.get("type") == "object", "must be all object schemas"
Expand Down Expand Up @@ -406,16 +403,37 @@ def _as_image_desc(cls, metadata: ImageMetadata) -> ImageDescription:
"md5sum": metadata.md5sum,
"filesize": metadata.filesize,
"filetype": FileType.IMAGE.value,
"MAPLatitude": round(metadata.lat, _COORDINATES_PRECISION),
"MAPLongitude": round(metadata.lon, _COORDINATES_PRECISION),
"MAPLatitude": round(
metadata.lat,
_fraction_decimal_digits(
metadata.lat, COORDINATE_BASE10_DIGIT_PLACES_PRECISION
),
),
"MAPLongitude": round(
metadata.lon,
_fraction_decimal_digits(
metadata.lon, COORDINATE_BASE10_DIGIT_PLACES_PRECISION
),
),
"MAPCaptureTime": build_capture_time(metadata.time),
}
if metadata.alt is not None:
desc["MAPAltitude"] = round(metadata.alt, _ALTITUDE_PRECISION)
desc["MAPAltitude"] = round(
metadata.alt,
_fraction_decimal_digits(
metadata.alt, ALTITUDE_BASE10_DIGIT_PLACES_PRECISION
),
)
if metadata.angle is not None:
direction: float = round(
metadata.angle,
_fraction_decimal_digits(
metadata.angle, DIRECTION_BASE10_DIGIT_PLACES_PRECISION
),
)
desc["MAPCompassHeading"] = {
"TrueHeading": round(metadata.angle, _ANGLE_PRECISION),
"MagneticHeading": round(metadata.angle, _ANGLE_PRECISION),
"TrueHeading": direction,
"MagneticHeading": direction,
}
fields = dataclasses.fields(metadata)
for field in fields:
Expand Down Expand Up @@ -498,10 +516,32 @@ class PointEncoder:
def encode(cls, p: geo.Point) -> T.Sequence[float | int | None]:
entry = [
int(p.time * 1000),
round(p.lon, _COORDINATES_PRECISION),
round(p.lat, _COORDINATES_PRECISION),
round(p.alt, _ALTITUDE_PRECISION) if p.alt is not None else None,
round(p.angle, _ANGLE_PRECISION) if p.angle is not None else None,
round(
p.lon,
_fraction_decimal_digits(
p.lon, COORDINATE_BASE10_DIGIT_PLACES_PRECISION
),
),
round(
p.lat,
_fraction_decimal_digits(
p.lat, COORDINATE_BASE10_DIGIT_PLACES_PRECISION
),
),
round(
p.alt,
_fraction_decimal_digits(p.alt, ALTITUDE_BASE10_DIGIT_PLACES_PRECISION),
)
if p.alt is not None
else None,
round(
p.angle,
_fraction_decimal_digits(
p.angle, DIRECTION_BASE10_DIGIT_PLACES_PRECISION
),
)
if p.angle is not None
else None,
]
return entry

Expand Down
Loading