fastgpx 0.2.2__tar.gz → 0.3.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {fastgpx-0.2.2 → fastgpx-0.3.0}/PKG-INFO +1 -1
- {fastgpx-0.2.2 → fastgpx-0.3.0}/pyproject.toml +1 -1
- {fastgpx-0.2.2 → fastgpx-0.3.0}/src/cpp/fastgpx/fastgpx.cpp +5 -1
- {fastgpx-0.2.2 → fastgpx-0.3.0}/src/cpp/fastgpx/fastgpx.hpp +1 -0
- {fastgpx-0.2.2 → fastgpx-0.3.0}/src/cpp/python_fastgpx.cpp +7 -1
- {fastgpx-0.2.2 → fastgpx-0.3.0}/src/cpp/python_utc_chrono.hpp +13 -1
- {fastgpx-0.2.2 → fastgpx-0.3.0}/src/fastgpx/__init__.pyi +1 -1
- {fastgpx-0.2.2 → fastgpx-0.3.0}/src/fastgpx/fastgpx/__init__.pyi +8 -0
- {fastgpx-0.2.2 → fastgpx-0.3.0}/tests/test_fastgpx.py +0 -1
- fastgpx-0.3.0/tests/test_time_bounds.py +73 -0
- {fastgpx-0.2.2 → fastgpx-0.3.0}/uv.lock +1 -1
- {fastgpx-0.2.2 → fastgpx-0.3.0}/.clang-format +0 -0
- {fastgpx-0.2.2 → fastgpx-0.3.0}/.gitignore +0 -0
- {fastgpx-0.2.2 → fastgpx-0.3.0}/.python-version +0 -0
- {fastgpx-0.2.2 → fastgpx-0.3.0}/CMakeLists.txt +0 -0
- {fastgpx-0.2.2 → fastgpx-0.3.0}/CMakeSettings.json +0 -0
- {fastgpx-0.2.2 → fastgpx-0.3.0}/Development.md +0 -0
- {fastgpx-0.2.2 → fastgpx-0.3.0}/GPX.md +0 -0
- {fastgpx-0.2.2 → fastgpx-0.3.0}/LICENSE.md +0 -0
- {fastgpx-0.2.2 → fastgpx-0.3.0}/README.md +0 -0
- {fastgpx-0.2.2 → fastgpx-0.3.0}/benchmarks/benchmark_gpx.py +0 -0
- {fastgpx-0.2.2 → fastgpx-0.3.0}/benchmarks/benchmark_polyline.py +0 -0
- {fastgpx-0.2.2 → fastgpx-0.3.0}/benchmarks/gpx_parse.md +0 -0
- {fastgpx-0.2.2 → fastgpx-0.3.0}/catch2.py +0 -0
- {fastgpx-0.2.2 → fastgpx-0.3.0}/coverage.bat +0 -0
- {fastgpx-0.2.2 → fastgpx-0.3.0}/datetime.md +0 -0
- {fastgpx-0.2.2 → fastgpx-0.3.0}/docs/Makefile +0 -0
- {fastgpx-0.2.2 → fastgpx-0.3.0}/docs/make.bat +0 -0
- {fastgpx-0.2.2 → fastgpx-0.3.0}/docs/source/api.rst +0 -0
- {fastgpx-0.2.2 → fastgpx-0.3.0}/docs/source/conf.py +0 -0
- {fastgpx-0.2.2 → fastgpx-0.3.0}/docs/source/index.rst +0 -0
- {fastgpx-0.2.2 → fastgpx-0.3.0}/docs/source/overview.rst +0 -0
- {fastgpx-0.2.2 → fastgpx-0.3.0}/profiling/profile_polyline.py +0 -0
- {fastgpx-0.2.2 → fastgpx-0.3.0}/pytest.ini +0 -0
- {fastgpx-0.2.2 → fastgpx-0.3.0}/src/cpp/CMakeLists.txt +0 -0
- {fastgpx-0.2.2 → fastgpx-0.3.0}/src/cpp/app.cpp +0 -0
- {fastgpx-0.2.2 → fastgpx-0.3.0}/src/cpp/expected_gpx_data.json +0 -0
- {fastgpx-0.2.2 → fastgpx-0.3.0}/src/cpp/fastgpx/datetime.cpp +0 -0
- {fastgpx-0.2.2 → fastgpx-0.3.0}/src/cpp/fastgpx/datetime.hpp +0 -0
- {fastgpx-0.2.2 → fastgpx-0.3.0}/src/cpp/fastgpx/datetime_test.cpp +0 -0
- {fastgpx-0.2.2 → fastgpx-0.3.0}/src/cpp/fastgpx/errors.cpp +0 -0
- {fastgpx-0.2.2 → fastgpx-0.3.0}/src/cpp/fastgpx/errors.hpp +0 -0
- {fastgpx-0.2.2 → fastgpx-0.3.0}/src/cpp/fastgpx/errors_test.cpp +0 -0
- {fastgpx-0.2.2 → fastgpx-0.3.0}/src/cpp/fastgpx/fastgpx_test.cpp +0 -0
- {fastgpx-0.2.2 → fastgpx-0.3.0}/src/cpp/fastgpx/filesystem.cpp +0 -0
- {fastgpx-0.2.2 → fastgpx-0.3.0}/src/cpp/fastgpx/filesystem.hpp +0 -0
- {fastgpx-0.2.2 → fastgpx-0.3.0}/src/cpp/fastgpx/filesystem_test.cpp +0 -0
- {fastgpx-0.2.2 → fastgpx-0.3.0}/src/cpp/fastgpx/geom.cpp +0 -0
- {fastgpx-0.2.2 → fastgpx-0.3.0}/src/cpp/fastgpx/geom.hpp +0 -0
- {fastgpx-0.2.2 → fastgpx-0.3.0}/src/cpp/fastgpx/geom_test.cpp +0 -0
- {fastgpx-0.2.2 → fastgpx-0.3.0}/src/cpp/fastgpx/polyline.cpp +0 -0
- {fastgpx-0.2.2 → fastgpx-0.3.0}/src/cpp/fastgpx/polyline.hpp +0 -0
- {fastgpx-0.2.2 → fastgpx-0.3.0}/src/cpp/fastgpx/test_data.cpp +0 -0
- {fastgpx-0.2.2 → fastgpx-0.3.0}/src/cpp/fastgpx/test_data.hpp +0 -0
- {fastgpx-0.2.2 → fastgpx-0.3.0}/src/cpp/fastgpx/test_data.json +0 -0
- {fastgpx-0.2.2 → fastgpx-0.3.0}/src/cpp/fastgpx/test_data_test.cpp +0 -0
- {fastgpx-0.2.2 → fastgpx-0.3.0}/src/fastgpx/__init__.py +0 -0
- {fastgpx-0.2.2 → fastgpx-0.3.0}/src/fastgpx/fastgpx/geo.pyi +0 -0
- {fastgpx-0.2.2 → fastgpx-0.3.0}/src/fastgpx/fastgpx/polyline.pyi +0 -0
- {fastgpx-0.2.2 → fastgpx-0.3.0}/src/fastgpx/py.typed +0 -0
- {fastgpx-0.2.2 → fastgpx-0.3.0}/tests/test_bounds.py +0 -0
- {fastgpx-0.2.2 → fastgpx-0.3.0}/tests/test_polyline.py +0 -0
@@ -43,10 +43,14 @@ std::chrono::system_clock::time_point TimePoint::value() const
|
|
43
43
|
|
44
44
|
bool TimeBounds::IsEmpty() const
|
45
45
|
{
|
46
|
-
assert(start_time.has_value() == end_time.has_value());
|
47
46
|
return !start_time.has_value() && !end_time.has_value();
|
48
47
|
}
|
49
48
|
|
49
|
+
bool TimeBounds::IsRange() const
|
50
|
+
{
|
51
|
+
return start_time.has_value() && end_time.has_value();
|
52
|
+
}
|
53
|
+
|
50
54
|
void TimeBounds::Add(const std::chrono::system_clock::time_point time_point)
|
51
55
|
{
|
52
56
|
if (start_time.has_value())
|
@@ -53,7 +53,13 @@ PYBIND11_MODULE(fastgpx, m)
|
|
53
53
|
py::arg("end_time"))
|
54
54
|
.def_readwrite("start_time", &fastgpx::TimeBounds::start_time)
|
55
55
|
.def_readwrite("end_time", &fastgpx::TimeBounds::end_time)
|
56
|
-
.def("is_empty", &fastgpx::TimeBounds::IsEmpty)
|
56
|
+
.def("is_empty", &fastgpx::TimeBounds::IsEmpty)
|
57
|
+
.def("is_range", &fastgpx::TimeBounds::IsRange)
|
58
|
+
.def("add",
|
59
|
+
py::overload_cast<std::chrono::system_clock::time_point>(&fastgpx::TimeBounds::Add),
|
60
|
+
py::arg("datetime"))
|
61
|
+
.def("add", py::overload_cast<const fastgpx::TimeBounds&>(&fastgpx::TimeBounds::Add),
|
62
|
+
py::arg("timebounds"));
|
57
63
|
|
58
64
|
py::class_<fastgpx::LatLong>(m, "LatLong")
|
59
65
|
.def(py::init<>())
|
@@ -27,6 +27,15 @@
|
|
27
27
|
namespace PYBIND11_NAMESPACE {
|
28
28
|
namespace detail {
|
29
29
|
|
30
|
+
inline std::time_t to_utc_time_t(std::tm* tm)
|
31
|
+
{
|
32
|
+
#if defined(_WIN32)
|
33
|
+
return _mkgmtime(tm);
|
34
|
+
#else
|
35
|
+
return timegm(tm);
|
36
|
+
#endif
|
37
|
+
}
|
38
|
+
|
30
39
|
template<typename type>
|
31
40
|
class duration_caster
|
32
41
|
{
|
@@ -195,7 +204,10 @@ public:
|
|
195
204
|
return false;
|
196
205
|
}
|
197
206
|
|
198
|
-
|
207
|
+
// HACK: Assume datetime.datetime objects are in UTC, so we use timegm instead of mktime.
|
208
|
+
// value = time_point_cast<Duration>(system_clock::from_time_t(std::mktime(&cal)) + msecs);
|
209
|
+
std::time_t tt = to_utc_time_t(&cal);
|
210
|
+
value = time_point_cast<Duration>(system_clock::from_time_t(tt) + msecs);
|
199
211
|
return true;
|
200
212
|
}
|
201
213
|
|
@@ -9,4 +9,4 @@ from fastgpx.fastgpx import geo
|
|
9
9
|
from fastgpx.fastgpx import parse
|
10
10
|
from fastgpx.fastgpx import polyline
|
11
11
|
from . import fastgpx
|
12
|
-
__all__ = ['Bounds', 'Gpx', 'LatLong', 'Segment', 'TimeBounds', 'Track', '
|
12
|
+
__all__: list = ['Bounds', 'Gpx', 'LatLong', 'Segment', 'TimeBounds', 'Track', 'geo', 'parse', 'polyline']
|
@@ -101,8 +101,16 @@ class TimeBounds:
|
|
101
101
|
@typing.overload
|
102
102
|
def __init__(self, start_time: datetime.datetime | None, end_time: datetime.datetime | None) -> None:
|
103
103
|
...
|
104
|
+
@typing.overload
|
105
|
+
def add(self, datetime: datetime.datetime) -> None:
|
106
|
+
...
|
107
|
+
@typing.overload
|
108
|
+
def add(self, timebounds: TimeBounds) -> None:
|
109
|
+
...
|
104
110
|
def is_empty(self) -> bool:
|
105
111
|
...
|
112
|
+
def is_range(self) -> bool:
|
113
|
+
...
|
106
114
|
class Track:
|
107
115
|
comment: str | None
|
108
116
|
description: str | None
|
@@ -0,0 +1,73 @@
|
|
1
|
+
from datetime import datetime
|
2
|
+
|
3
|
+
import fastgpx
|
4
|
+
|
5
|
+
|
6
|
+
class TestTimeBounds:
|
7
|
+
|
8
|
+
def test_init_defaults(self):
|
9
|
+
bounds = fastgpx.TimeBounds()
|
10
|
+
assert bounds.is_empty()
|
11
|
+
assert not bounds.is_range()
|
12
|
+
assert bounds.start_time is None
|
13
|
+
assert bounds.end_time is None
|
14
|
+
|
15
|
+
def test_init_with_start_time(self):
|
16
|
+
start_time = datetime.fromisoformat("2025-06-20 08:07:28+00:00")
|
17
|
+
bounds = fastgpx.TimeBounds(start_time=start_time, end_time=None)
|
18
|
+
assert not bounds.is_empty()
|
19
|
+
assert not bounds.is_range()
|
20
|
+
assert bounds.start_time == start_time
|
21
|
+
assert bounds.end_time is None
|
22
|
+
|
23
|
+
def test_init_with_end_time(self):
|
24
|
+
end_time = datetime.fromisoformat("2025-06-27 13:37:00+00:00")
|
25
|
+
bounds = fastgpx.TimeBounds(start_time=None, end_time=end_time)
|
26
|
+
assert not bounds.is_empty()
|
27
|
+
assert not bounds.is_range()
|
28
|
+
assert bounds.start_time is None
|
29
|
+
assert bounds.end_time == end_time
|
30
|
+
|
31
|
+
def test_init_with_start_and_end_time(self):
|
32
|
+
start_time = datetime.fromisoformat("2025-06-20 08:07:28+00:00")
|
33
|
+
end_time = datetime.fromisoformat("2025-06-27 13:37:00+00:00")
|
34
|
+
bounds = fastgpx.TimeBounds(start_time=start_time, end_time=end_time)
|
35
|
+
assert not bounds.is_empty()
|
36
|
+
assert bounds.is_range()
|
37
|
+
assert bounds.start_time == start_time
|
38
|
+
assert bounds.end_time == end_time
|
39
|
+
|
40
|
+
def test_add_single_time_point(self):
|
41
|
+
bounds = fastgpx.TimeBounds()
|
42
|
+
time_point = datetime.fromisoformat("2025-06-20 08:07:28+00:00")
|
43
|
+
bounds.add(time_point)
|
44
|
+
assert not bounds.is_empty()
|
45
|
+
assert bounds.is_range()
|
46
|
+
assert bounds.start_time == time_point
|
47
|
+
assert bounds.end_time == time_point
|
48
|
+
|
49
|
+
def test_add_second_time_point(self):
|
50
|
+
bounds = fastgpx.TimeBounds()
|
51
|
+
time_point1 = datetime.fromisoformat("2025-06-20 08:07:28+00:00")
|
52
|
+
time_point2 = datetime.fromisoformat("2025-06-27 13:37:00+00:00")
|
53
|
+
bounds.add(time_point1)
|
54
|
+
bounds.add(time_point2)
|
55
|
+
assert not bounds.is_empty()
|
56
|
+
assert bounds.is_range()
|
57
|
+
assert bounds.start_time == time_point1
|
58
|
+
assert bounds.end_time == time_point2
|
59
|
+
|
60
|
+
def test_add_time_bounds(self):
|
61
|
+
bounds1 = fastgpx.TimeBounds(
|
62
|
+
start_time=datetime.fromisoformat("2025-06-20 08:07:28+00:00"),
|
63
|
+
end_time=datetime.fromisoformat("2025-06-27 13:37:00+00:00")
|
64
|
+
)
|
65
|
+
bounds2 = fastgpx.TimeBounds(
|
66
|
+
start_time=datetime.fromisoformat("2025-06-25 10:00:00+00:00"),
|
67
|
+
end_time=datetime.fromisoformat("2025-06-30 15:00:00+00:00")
|
68
|
+
)
|
69
|
+
bounds1.add(bounds2)
|
70
|
+
assert not bounds1.is_empty()
|
71
|
+
assert bounds1.is_range()
|
72
|
+
assert bounds1.start_time == bounds1.start_time
|
73
|
+
assert bounds1.end_time == bounds2.end_time
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|