Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Performance improvement #161

Merged
merged 4 commits into from
Oct 17, 2024
Merged
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
5 changes: 5 additions & 0 deletions CHANGES.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,9 @@

## 6.1.0 (TBD)

* add `_tile_matrices_idx: Dict[str, int]` private attribute to improve `matrices` lookup
* change `xy_bounds()` and `bounds()` methods to avoid calculation duplication

## 6.0.0 (2024-10-16)

* remove `_geographic_crs` private attribute in `TileMatrixSet` model **breaking change**
Expand Down
36 changes: 28 additions & 8 deletions morecantile/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -488,10 +488,16 @@ class TileMatrixSet(BaseModel, arbitrary_types_allowed=True):
_to_geographic: pyproj.Transformer = PrivateAttr()
_from_geographic: pyproj.Transformer = PrivateAttr()

_tile_matrices_idx: Dict[int, int] = PrivateAttr()

def __init__(self, **data):
"""Set private attributes."""
super().__init__(**data)

self._tile_matrices_idx = {
int(mat.id): idx for idx, mat in enumerate(self.tileMatrices)
vincentsarago marked this conversation as resolved.
Show resolved Hide resolved
}

try:
self._to_geographic = pyproj.Transformer.from_crs(
self.crs._pyproj_crs, self.crs._pyproj_crs.geodetic_crs, always_xy=True
Expand Down Expand Up @@ -765,9 +771,8 @@ def custom(

def matrix(self, zoom: int) -> TileMatrix:
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why not use lru_cache here?

I've read some article that mentioned that using lru cache for class method might result in memory leaks 🤷

"""Return the TileMatrix for a specific zoom."""
for m in self.tileMatrices:
if m.id == str(zoom):
return m
if (idx := self._tile_matrices_idx.get(zoom, None)) is not None:
return self.tileMatrices[idx]

#######################################################################
# If user wants a deeper matrix we calculate it
Expand Down Expand Up @@ -1093,8 +1098,23 @@ def xy_bounds(self, *tile: Tile) -> BoundingBox:
"""
t = _parse_tile_arg(*tile)

left, top = self._ul(t)
right, bottom = self._lr(t)
matrix = self.matrix(t.z)
origin_x, origin_y = self._matrix_origin(matrix)

cf = (
matrix.get_coalesce_factor(t.y)
if matrix.variableMatrixWidths is not None
else 1
)

left = origin_x + math.floor(t.x / cf) * matrix.cellSize * cf * matrix.tileWidth
top = origin_y - t.y * matrix.cellSize * matrix.tileHeight
right = (
origin_x
+ (math.floor(t.x / cf) + 1) * matrix.cellSize * cf * matrix.tileWidth
)
bottom = origin_y - (t.y + 1) * matrix.cellSize * matrix.tileHeight
Copy link
Member Author

@vincentsarago vincentsarago Oct 16, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

do all the calculation here instead of calling _ul and _lr method which will duplicate some stuff (matrix lookup, origin, coalecense)

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

cons: we end up having duplicated code


return BoundingBox(left, bottom, right, top)

def ul(self, *tile: Tile) -> Coords:
Expand Down Expand Up @@ -1146,10 +1166,10 @@ def bounds(self, *tile: Tile) -> BoundingBox:
BoundingBox: The bounding box of the input tile.

"""
t = _parse_tile_arg(*tile)
_left, _bottom, _right, _top = self.xy_bounds(*tile)
left, top = self.lnglat(_left, _top)
right, bottom = self.lnglat(_right, _bottom)
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

use the fastest xy_bounds methods instead of ul and lr methods


left, top = self.ul(t)
right, bottom = self.lr(t)
return BoundingBox(left, bottom, right, top)

@property
Expand Down
Loading