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
22 changes: 14 additions & 8 deletions docling_core/types/doc/tokens.py
Original file line number Diff line number Diff line change
Expand Up @@ -302,14 +302,20 @@ def get_location(
ysize: int = 500, # TODO review
self_closing: bool = False,
):
"""Get the location string give bbox and page-dim."""
assert bbox[0] <= bbox[2], f"bbox[0]<=bbox[2] => {bbox[0]}<={bbox[2]}"
assert bbox[1] <= bbox[3], f"bbox[1]<=bbox[3] => {bbox[1]}<={bbox[3]}"

x0 = bbox[0] / page_w
y0 = bbox[1] / page_h
x1 = bbox[2] / page_w
y1 = bbox[3] / page_h
"""Get the location string given bbox and page-dim."""
# Normalize potentially inverted coordinates instead of asserting on
# them. Near-degenerate elements (e.g. a thin rule whose layout-model
# regression produced a slightly inverted bbox) can arrive with
# bbox[0] > bbox[2] or bbox[1] > bbox[3]. The min()/max() calls below
# already emit correctly-ordered tokens, so sorting here mirrors that
# normalization and avoids crashing export_to_doctags on valid output.
left, right = sorted((bbox[0], bbox[2]))
top, bottom = sorted((bbox[1], bbox[3]))

x0 = left / page_w
y0 = top / page_h
x1 = right / page_w
y1 = bottom / page_h

x0_tok = DocumentToken.get_location_token(val=min(x0, x1), rnorm=xsize, self_closing=self_closing)
y0_tok = DocumentToken.get_location_token(val=min(y0, y1), rnorm=ysize, self_closing=self_closing)
Expand Down
51 changes: 51 additions & 0 deletions test/test_tokens.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
"""Unit tests for document tokens."""

from docling_core.types.doc.tokens import DocumentToken


def test_get_location_normal_bbox():
"""A well-ordered bbox produces correctly-ordered location tokens."""
loc = DocumentToken.get_location(
bbox=(100.0, 200.0, 300.0, 400.0),
page_w=1000.0,
page_h=1000.0,
)
assert loc == "<loc_50><loc_100><loc_150><loc_200>"


def test_get_location_inverted_bbox_does_not_crash():
"""A near-degenerate, slightly inverted bbox must not raise.

Regression test for #620: layout-model regression can emit a bbox with
bbox[1] > bbox[3] (or bbox[0] > bbox[2]) on thin/degenerate elements.
get_location already normalizes coordinates via min()/max() downstream,
so it should serialize such boxes instead of crashing export_to_doctags.
"""
# bbox from the issue: y is inverted by 7.7pt (633.39 > 625.68).
inverted = DocumentToken.get_location(
bbox=(0.0, 633.3925132751465, 100.0, 625.6789665222168),
page_w=1000.0,
page_h=1000.0,
)
# The result must equal the same box with y-coordinates ordered correctly.
normalized = DocumentToken.get_location(
bbox=(0.0, 625.6789665222168, 100.0, 633.3925132751465),
page_w=1000.0,
page_h=1000.0,
)
assert inverted == normalized


def test_get_location_fully_inverted_bbox():
"""Both axes inverted still normalizes to the ordered box."""
inverted = DocumentToken.get_location(
bbox=(300.0, 400.0, 100.0, 200.0),
page_w=1000.0,
page_h=1000.0,
)
ordered = DocumentToken.get_location(
bbox=(100.0, 200.0, 300.0, 400.0),
page_w=1000.0,
page_h=1000.0,
)
assert inverted == ordered
Loading