§
    �Øj`  ã                   óú   — d Z ddlmZ ddlmZ ddlZddlmZmZm	Z	m
Z
mZmZ dZdZdZd	Zd
ZdZdZ edd¦  «        Zd„ Zdddœd„Zd„ Zd„ Zd„ Zd„ Zd„ Zd„ Zd„ Zd„ Zd„ Zd„ Z d„ Z!d„ Z"d„ Z#d„ Z$d „ Z%dddœd!„Z&dS )"aÖ  
Copyright (C) 2023 Artifex Software, Inc.

This file is part of PyMuPDF.

PyMuPDF is free software: you can redistribute it and/or modify it under the
terms of the GNU Affero General Public License as published by the Free
Software Foundation, either version 3 of the License, or (at your option)
any later version.

PyMuPDF is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
details.

You should have received a copy of the GNU Affero General Public License
along with MuPDF. If not, see <https://www.gnu.org/licenses/agpl-3.0.en.html>

Alternative licensing terms are available from the licensor.
For commercial licensing, see <https://www.artifex.com/> or contact
Artifex Software, Inc., 39 Mesa Street, Suite 108A, San Francisco,
CA 94129, USA, for further information.

---------------------------------------------------------------------

PyMuPDF table union stage, behind find_tables(union=True): fuse the layout
analyzer's table grids with the line-based finder's candidates. Table,
TableFinder and _iou come from pymupdf.table; find_tables is imported lazily.
é    )Úbisect_left)Ú
namedtupleN)ÚCHARSÚEDGESÚTableÚTableFinderÚ_cells_to_rowsÚ_iouÚlines_strictgÍÌÌÌÌÌì?Tg      @g333333ë?g      Ð?gš™™™™™é?Ú_UnionContentz1supported dense_rows dense_columns concrete slotsc                 ó$  ‡‡— g }| j         pg D �]€}t          |t          ¦  «        sŒ|                     d¦  «        dk    rŒ3|                     d¦  «        }|                     d¦  «        }|r|€Œb|d         |d         |d         |d	         f\  ŠŠ}}‰gˆfd
„|j        D ¦   «         z   |gz   }‰gˆfd„|j        D ¦   «         z   |gz   }g }	t          t          |¦  «        dz
  ¦  «        D ]r}
g }t          t          |¦  «        dz
  ¦  «        D ]9}|                     ||         ||
         ||dz            ||
dz            f¦  «         Œ:|	                     |¦  «         Œs|                     t          j
        |dd…         ¦  «        |	f¦  «         �Œ‚|S )at  Primary table grids from the raw layout analyzer result.

    Reads page.layout_information in its raw (return_raw=True) form and yields a
    ``(bbox, grid)`` pair per "table" group -- ``grid`` is the full row-major cell
    grid built from the group box plus its interior GridPrediction lines, in
    layout (reading) order. Boxes without a usable grid are skipped.
    Ú
class_nameÚtableÚ
group_bboxÚ
table_gridNr   é   é   é   c                 ó   •— g | ]}|‰z   ‘ŒS © r   )Ú.0ÚhÚy0s     €ú‰/Users/tedpeters/Documents/Projects/Claude Projects/Misc Tools/notename-sheets/.venv/lib/python3.11/site-packages/pymupdf/_table_union.pyú
<listcomp>z'_layout_table_grids.<locals>.<listcomp>X   ó   ø€ Ð<Ð<Ð< Q˜!˜b™&Ð<Ð<Ð<ó    c                 ó   •— g | ]}|‰z   ‘ŒS r   r   )r   ÚvÚx0s     €r   r   z'_layout_table_grids.<locals>.<listcomp>Y   r   r   é   )Úlayout_informationÚ
isinstanceÚdictÚgetÚh_linesÚv_linesÚrangeÚlenÚappendÚpymupdfÚRect)ÚpageÚgridsÚgroupr   Ú	grid_predÚx1Úy1r&   r'   ÚgridÚiÚrowÚjr    r   s                @@r   Ú_layout_table_gridsr7   C   sÏ  øø€ ð €EØÔ)Ð/¨Rð ;ñ ;ˆÝ˜%¥Ñ&Ô&ð 	ð Ø�9Š9�\Ñ"Ô" gÒ-Ð-ØØ—Y’Y˜|Ñ,Ô,ˆ
Ø—I’I˜lÑ+Ô+ˆ	Øð 	˜YÐ.ØØ# Aœ¨
°1¬°zÀ!´}ÀjÐQRÄmÐS‰ˆˆB��BØ�$Ð<Ð<Ð<Ð<¨)Ô*;Ð<Ñ<Ô<Ñ<À¸tÑCˆØ�$Ð<Ð<Ð<Ð<¨)Ô*;Ð<Ñ<Ô<Ñ<À¸tÑCˆØˆÝ•s˜7‘|”| aÑ'Ñ(Ô(ð 	ð 	ˆAØˆCÝ�3˜w™<œ<¨!Ñ+Ñ,Ô,ð Uð U�Ø—
’
˜G AœJ¨°¬
°G¸AÀ¹E´NÀGÈAÐPQÉEÄNÐSÑTÔTÐTÐTØ�KŠK˜ÑÔÐÐØ�Š•g”l :¨b¨q¨b¤>Ñ2Ô2°DÐ9Ñ:Ô:Ð:Ñ:Ø€Lr   ©Ú	add_linesÚ	add_boxesc                ó~   ‡— ddl m} g Šˆfd„} || t          d|||¬¦  «        }|€‰                     ¦   «          ‰|fS )an  Line-based table candidates for the union stage as ``(bbox, grid)`` pairs.

    Runs a nested find_tables (strategy=_UNION_STRATEGY, use_layout=False) and
    keeps each detected table's bbox and row-major cell grid (None for a gap),
    deduped by rounded bbox. Caller-supplied virtual lines / boxes are forwarded
    to that nested finder so they take part in the same union decisions as
    PDF-native vector rules. Admission (see ``admit``) runs on the finder's cell
    groups, before a Table is built for any of them. Returns ``(candidates,
    finder)``; the finder is reused as the returned TableFinder shell.
    r   )Úfind_tablesc           
      óê  •— g }t          ¦   «         }d}|D �][}t          j        t          d„ |D ¦   «         ¦  «        t          d„ |D ¦   «         ¦  «        t	          d„ |D ¦   «         ¦  «        t	          d„ |D ¦   «         ¦  «        ¦  «        }|j        rŒ~d„ t          |¦  «        D ¦   «         }|sŒšt          d„ |D ¦   «         ¦  «        }||v rŒ¸t          | |¦  «        rR|€t          ¦   «         }t          ||¦  «        }	|	j        r)|	j        dk    r|	j        dk    r|	j        dz  |	j        k    s�Œ|                     |¦  «         |                     |¦  «         ‰
                     ||f¦  «         �Œ]|S )	aõ  Keep the cell groups that may become tables, in detection order.

        A candidate is admitted as before: the line grid is evidence in its own
        right and the layout model can miss a table entirely. The one exception is
        a candidate sitting inside a region the layout model called a picture,
        which has to show table-shaped text instead. That cheap geometric test
        therefore gates the character scan, and the scan itself is built once for
        the whole call.
        Nc              3   ó&   K  — | ]}|d          V — ŒdS )r   Nr   ©r   Úcells     r   ú	<genexpr>z8_union_line_candidates.<locals>.admit.<locals>.<genexpr>ƒ   ó&   è è € Ð.Ð. �D˜”GÐ.Ð.Ð.Ð.Ð.Ð.r   c              3   ó&   K  — | ]}|d          V — ŒdS )r   Nr   r?   s     r   rA   z8_union_line_candidates.<locals>.admit.<locals>.<genexpr>„   rB   r   c              3   ó&   K  — | ]}|d          V — ŒdS ©r   Nr   r?   s     r   rA   z8_union_line_candidates.<locals>.admit.<locals>.<genexpr>…   rB   r   c              3   ó&   K  — | ]}|d          V — ŒdS )r   Nr   r?   s     r   rA   z8_union_line_candidates.<locals>.admit.<locals>.<genexpr>†   rB   r   c                 ó   — g | ]	}|j         ‘Œ
S r   )Úcells©r   r5   s     r   r   z9_union_line_candidates.<locals>.admit.<locals>.<listcomp>Š   s   € Ð?Ð?Ð? #�C”IÐ?Ð?Ð?r   c              3   ó4   K  — | ]}t          |¦  «        V — Œd S ©N)Úround)r   Úvalues     r   rA   z8_union_line_candidates.<locals>.admit.<locals>.<genexpr>�   s(   è è € Ð7Ð7¨�˜e™œÐ7Ð7Ð7Ð7Ð7Ð7r   r   )Úsetr+   r,   ÚminÚmaxÚis_emptyr	   ÚtupleÚ_union_candidate_inside_pictureÚ_union_char_midpointsÚ_union_grid_content_supportÚ	supportedÚ
dense_rowsÚdense_columnsÚconcreteÚslotsÚaddr*   )Ú	live_pageÚgroupsÚkeptÚseenÚpointsrH   Úbboxr3   ÚkeyÚcontentÚ
candidatess             €r   Úadmitz%_union_line_candidates.<locals>.admitt   s²  ø€ ð ˆÝ‰uŒuˆØˆØð "	,ñ "	,ˆEÝ”<ÝÐ.Ð.¨Ð.Ñ.Ô.Ñ.Ô.ÝÐ.Ð.¨Ð.Ñ.Ô.Ñ.Ô.ÝÐ.Ð.¨Ð.Ñ.Ô.Ñ.Ô.ÝÐ.Ð.¨Ð.Ñ.Ô.Ñ.Ô.ñ	ô ˆDð Œ}ð ØØ?Ð?­¸Ñ)>Ô)>Ð?Ñ?Ô?ˆDØð ØÝÐ7Ð7°$Ð7Ñ7Ô7Ñ7Ô7ˆCØ�dˆ{ˆ{ØÝ.¨y¸$Ñ?Ô?ð Ø�>Ý2Ñ4Ô4�FÝ5°d¸FÑCÔC�ð Ô%ðàÔ*¨aÒ/Ð/ØÔ-°Ò2Ð2ØÔ(¨1Ñ,°´Ò=Ð=áð �HŠH�S‰MŒMˆMØ�KŠK˜ÑÔÐØ×Ò˜t T˜lÑ+Ô+Ð+Ñ+Øˆr   F)ÚstrategyÚ
use_layoutr9   r:   Ú_cell_group_filter)Úpymupdf.tabler<   Ú_UNION_STRATEGYÚclear)r-   r9   r:   r<   re   Úfinderrd   s         @r   Ú_union_line_candidatesrm   d   s„   ø€ ð *Ð)Ð)Ð)Ð)Ð)Ø€Jð0ð 0ð 0ð 0ð 0ðd ˆ[ØÝ ØØØØ ðñ ô €Fð €~à×ÒÑÔÐØ�vÐÐr   c                 ó¬   — t          dt          | j        | j        z
  ¦  «        ¦  «        t          dt          | j        | j        z
  ¦  «        ¦  «        z  S ©Nç        )rP   Úfloatr1   r    r2   r   )Úrects    r   Ú_union_rect_arears   ´   sC   € Ýˆs•E˜$œ' D¤GÑ+Ñ,Ô,Ñ-Ô-µ°C½¸t¼wÈÌÑ?PÑ9QÔ9QÑ0RÔ0RÑRÐRr   c                 óÔ  — t          t          | j        ¦  «        t          |j        ¦  «        ¦  «        }t          t          | j        ¦  «        t          |j        ¦  «        ¦  «        }t	          t          | j        ¦  «        t          |j        ¦  «        ¦  «        }t	          t          | j        ¦  «        t          |j        ¦  «        ¦  «        }||k    s||k    rdS ||z
  ||z
  z  S ro   )rP   rq   r    r   rO   r1   r2   )ÚleftÚrightr    r   r1   r2   s         r   Ú_union_intersection_arearw   ¸   s§   € Ý	�U�4”7‰^Œ^�U 5¤8™_œ_Ñ	-Ô	-€BÝ	�U�4”7‰^Œ^�U 5¤8™_œ_Ñ	-Ô	-€BÝ	�U�4”7‰^Œ^�U 5¤8™_œ_Ñ	-Ô	-€BÝ	�U�4”7‰^Œ^�U 5¤8™_œ_Ñ	-Ô	-€BØ	ˆR‚x€x�2˜’8�8ØˆsØ�‰G˜˜R™Ñ Ð r   c           
      óð   — t          dt          t          | j        ¦  «        t          |j        ¦  «        ¦  «        t          t          | j        ¦  «        t          |j        ¦  «        ¦  «        z
  ¦  «        S ro   )rP   rO   rq   r1   r    )ru   rv   s     r   Ú_union_x_overlapry   Â   sM   € Ýˆs•C�˜dœg™œ­¨e¬h©¬Ñ8Ô8½3½uÀTÄW¹~¼~ÍuÐUZÔU]ÉÌÑ;_Ô;_Ñ_Ñ`Ô`Ð`r   c                 ó6  — t          | ¦  «        }|dk    rdS d}d}d}t          |¦  «        D ]i\  }}t          |¦  «        }t          | |¦  «        }	|	dk    s|dk    rŒ1|	|z  }
|	|z  }|
t          k    r|
|k    r|}|
}ŒQ|
t          k    s|t          k    rd}Œj||fS )a2  The primary a split candidate belongs inside, plus an ambiguity flag.

    Returns ``(owner_index, ambiguous)``: owner is the best-contained primary
    (candidate>=_UNION_OWNER_CONTAINMENT inside it), else None; ambiguous is True
    when the candidate overlaps some primary enough to be unsafe to append.r   )NTNrp   FT)rs   Ú	enumeraterw   Ú_UNION_OWNER_CONTAINMENTÚ_UNION_OWNER_AMBIGUOUS_OVERLAP)Úcandidate_bboxÚexisting_bboxesÚcandidate_areaÚ
best_ownerÚbest_containmentÚ	ambiguousÚindexÚexisting_bboxÚexisting_areaÚ
inter_areaÚcandidate_containmentÚexisting_coverages               r   Ú_union_find_ownerrŠ   Æ   sä   € õ & nÑ5Ô5€NØ˜ÒÐØˆzØ€JØÐØ€IÝ )¨/Ñ :Ô :ð ð Ñˆˆ}Ý(¨Ñ7Ô7ˆÝ-¨n¸mÑLÔLˆ
Ø˜Š?ˆ?˜m¨qÒ0Ð0ØØ *¨^Ñ ;ÐØ&¨Ñ6ÐØ Õ$<Ò<Ð<ÐAVÐYiÒAiÐAiØˆJØ4ÐÐØ"Õ&DÒDÐDÐHYÕ]{ÒH{ÐH{ØˆIøØ�yÐ Ð r   c                  óØ  — g } t           D ]Ë}t          |                     d¦  «        pd¦  «                             ¦   «         sŒ9	 t	          |d         ¦  «        t	          |d         ¦  «        z   dz  }t	          |d         ¦  «        t	          |d         ¦  «        z   dz  }n# t
          t          t          f$ r Y Œ°w xY w|                      ||f¦  «         ŒÌ|  	                    ¦   «          | S )a!  The page's non-blank character midpoints as ``(v_mid, h_mid)``, y-sorted.

    One pass over CHARS replaces the per-cell character scan of the admission
    tests, which read midpoints only. Sorting by the vertical midpoint lets each
    grid row take its own characters as one slice.
    ÚtextÚ r    r1   ç       @ÚtopÚbottom)
r   Ústrr%   Ústriprq   ÚKeyErrorÚ	TypeErrorÚ
ValueErrorr*   Úsort)r`   ÚcharÚh_midÚv_mids       r   rT   rT   á   sï   € ð €FÝð &ð &ˆÝ�4—8’8˜FÑ#Ô#Ð) rÑ*Ô*×0Ò0Ñ2Ô2ð 	Øð	Ý˜4 œ:Ñ&Ô&­¨t°D¬zÑ):Ô):Ñ:¸cÑAˆEÝ˜4 œ;Ñ'Ô'­%°°X´Ñ*?Ô*?Ñ?À3ÑFˆEˆEøÝ�)¥ZÐ0ð 	ð 	ð 	ØˆHð	øøøà�Š�u˜e�nÑ%Ô%Ð%Ð%Ø
‡K‚K�M„M€MØ€Ms   ÁAB!Â!B;Â:B;c                 ó  ‡‡— t          d„ | D ¦   «         ¦  «        }t          d„ | D ¦   «         d¬¦  «        }dg|z  }dg|z  }g Šg }d}d}| D �]}	|t          |	¦  «        z  }t          ¦   «         }
d}d„ t	          |	¦  «        D ¦   «         }d„ |D ¦   «         }|t          |¦  «        z  }|r�t          ||¦  «        }|D ]n\  }Š||xx         dz  cc<   t          ‰|¦  «        sŒ&|dz  }||xx         dz  cc<   ˆfd„t	          |¦  «        D ¦   «         }|
                     |p|f¦  «         Œo‰                     |
¦  «         |                     |t          |¦  «        f¦  «         �Œt          d	„ ‰D ¦   «         ¦  «        d
k    o8t          ˆfd„t          t          |¦  «        ¦  «        D ¦   «         ¦  «        d
k    }t          |t          d„ |D ¦   «         ¦  «        t          d„ t          ||¦  «        D ¦   «         ¦  «        ||¬¦  «        S )a~  How a candidate line grid's text is distributed, in one scan.

    ``supported`` means at least two rows with text in at least two columns and
    at least two columns with text in at least two rows -- two being the smallest
    non-trivial count in each dimension, not a fitted one. A populated cell counts
    for every column its x-range covers, so a grid whose missing horizontal rules
    leave a spanning header above one record row is supported just like the same
    table with all its rules.

    ``dense_rows`` / ``dense_columns`` count the rows and columns whose own
    concrete cells are at least half populated, and ``concrete`` / ``slots`` are
    the concrete cells and the grid's total slots. Those describe the *shape* of
    the text rather than its amount, which is what separates a chart from a
    sparse table (see _union_candidate_inside_picture).

    Character membership follows Table.extract()'s half-open cell rule. ``None``
    grid slots are span/gap placeholders, not empty text cells. The decision is
    candidate-local: page area, layout ownership, file identity and virtual-line
    provenance are not inputs.
    c                 óF   — h | ]}|D ]}|®t          |d         ¦  «        ’ŒŒS ©Nr   )rq   ©r   r5   r@   s      r   ú	<setcomp>z._union_grid_content_support.<locals>.<setcomp>  s4   € ÐYÐYÐY¨ÀÐYÐY¸ÈÐHX•e˜D œG‘n”nÐHXÐHXÐHXÐHXr   c              3   ó4   K  — | ]}t          |¦  «        V — Œd S rK   ©r)   rI   s     r   rA   z._union_grid_content_support.<locals>.<genexpr>  s(   è è € Ð*Ð*˜c•�S‘”Ð*Ð*Ð*Ð*Ð*Ð*r   r   )Údefaultc                 óD   — g | ]\  }}|®|t          j        |¦  «        f‘ŒS rK   )r+   r,   )r   r„   r@   s      r   r   z/_union_grid_content_support.<locals>.<listcomp>  s1   € ÐcÐcÐc±°¸ÐRVÐRb�%�œ dÑ+Ô+Ð,ÐRbÐRbÐRbr   c                 ó*   — g | ]\  }}|j         °||f‘ŒS r   )rQ   )r   r„   rr   s      r   r   z/_union_grid_content_support.<locals>.<listcomp>  s'   € ÐMÐMÐM¡; 5¨$¸t¼}ÐM�%˜�ÐMÐMÐMr   r   c                 ó‚   •— g | ];\  }}t          ‰j        ¦  «        |cxk    rt          ‰j        ¦  «        k     ¯6n n|‘Œ<S r   )rq   r    r1   )r   ÚcolumnÚxrr   s      €r   r   z/_union_grid_content_support.<locals>.<listcomp>"  sY   ø€ ð ð ð á!˜ Ý˜TœW‘~”~¨Ð;Ð;Ò;Ð;­U°4´7©^¬^Ò;Ð;Ð;Ð;Ð;ð à;Ð;Ð;r   c              3   ó<   K  — | ]}t          |¦  «        d k    V — ŒdS rE   r    )r   Úcovereds     r   rA   z._union_grid_content_support.<locals>.<genexpr>*  s-   è è € ÐAÐA¨'•C˜‘L”L AÒ%ÐAÐAÐAÐAÐAÐAr   r   c              3   óX   •‡K  — | ]#Št          ˆfd „‰D ¦   «         ¦  «        dk    V — Œ$dS )c              3   ó    •K  — | ]}‰|v V — Œ	d S rK   r   )r   r¨   r¥   s     €r   rA   z8_union_grid_content_support.<locals>.<genexpr>.<genexpr>+  s(   øè è € Ð9Ð9 'ˆF�gÐÐ9Ð9Ð9Ð9Ð9Ð9r   r   N)Úsum)r   r¥   Úrow_columnss    @€r   rA   z._union_grid_content_support.<locals>.<genexpr>*  sb   øøè è € ð Oð Oàõ 	Ð9Ð9Ð9Ð9¨[Ð9Ñ9Ô9Ñ9Ô9¸QÒ>ðOð Oð Oð Oð Oð Or   c              3   ó:   K  — | ]\  }}|d k    o|dz  |k    V — ŒdS ©r   r   Nr   ©r   ÚfilledÚtotals      r   rA   z._union_grid_content_support.<locals>.<genexpr>0  s8   è è € ÐYÐY¹]¸VÀU�u˜q’yÐ8 V¨a¡Z°5Ò%8ÐYÐYÐYÐYÐYÐYr   c              3   ó:   K  — | ]\  }}|d k    o|dz  |k    V — ŒdS r®   r   r¯   s      r   rA   z._union_grid_content_support.<locals>.<genexpr>1  sL   è è € ð 
ð 
á�˜ð �AŠIÐ-˜& 1™*¨Ò-ð
ð 
ð 
ð 
ð 
ð 
r   )rV   rW   rX   rY   rZ   )ÚsortedrP   r)   rN   r{   Ú_union_row_pointsÚ_union_rect_has_pointÚupdater*   r«   r(   r   Úzip)r3   r`   ÚcolumnsÚwidthÚcolumn_populatedÚcolumn_concreteÚ
row_countsrY   rZ   r5   r¨   Úrow_populatedÚrectsÚbandr„   ÚspannedrV   rr   r¬   s                    @@r   rU   rU   ö   sÈ  øø€ õ* ÐYÐY°ÐYÑYÔYÑZÔZ€GÝÐ*Ð* TÐ*Ñ*Ô*°AÐ6Ñ6Ô6€EØ�s˜U‘{ÐØ�c˜E‘k€OØ€KØ€JØ€HØ€EØð 7ñ 7ˆØ•�S‘”ÑˆÝ‘%”%ˆØˆØcÐcÅ	È#ÁÄÐcÑcÔcˆØMÐM°%ÐMÑMÔMˆØ•C˜‘J”JÑˆØð 	4Ý$ U¨FÑ3Ô3ˆDØ$ð 4ð 4‘��tØ Ð&Ð&Ô&¨!Ñ+Ð&Ð&Ñ&Ý,¨T°4Ñ8Ô8ð ØØ Ñ"�Ø  Ð'Ð'Ô'¨1Ñ,Ð'Ð'Ñ'ðð ð ð å%.¨wÑ%7Ô%7ðñ ô �ð
 —’˜wÐ2¨5¨(Ñ3Ô3Ð3Ð3Ø×Ò˜7Ñ#Ô#Ð#Ø×Ò˜=­#¨e©*¬*Ð5Ñ6Ô6Ð6Ñ6ÝÐAÐA°[ÐAÑAÔAÑAÔAÀQÒFð Í3ð Oð Oð Oð Oå�C ™LœLÑ)Ô)ðOñ Oô Oñ Lô Lð 
òL€Iõ ØÝÐYÐYÈjÐYÑYÔYÑYÔYÝð 
ð 
å!$Ð%5°Ñ!GÔ!Gð
ñ 
ô 
ñ 
ô 
ð Øð	ñ 	ô 	ð 	r   c                 ó¶   — t          d„ | D ¦   «         ¦  «        }t          d„ | D ¦   «         ¦  «        }|t          ||f¦  «        t          ||f¦  «        …         S )z?The y-sorted midpoints falling in one grid row's vertical band.c              3   óD   K  — | ]\  }}t          |j        ¦  «        V — Œd S rK   )rq   r   ©r   Ú_indexrr   s      r   rA   z$_union_row_points.<locals>.<genexpr><  ó.   è è € Ð6Ð6¡ ¨�U�4”7‰^Œ^Ð6Ð6Ð6Ð6Ð6Ð6r   c              3   óD   K  — | ]\  }}t          |j        ¦  «        V — Œd S rK   )rq   r2   rÃ   s      r   rA   z$_union_row_points.<locals>.<genexpr>=  rÅ   r   )rO   rP   r   )r¾   r`   r   r2   s       r   r´   r´   :  sb   € å	Ð6Ð6°Ð6Ñ6Ô6Ñ	6Ô	6€BÝ	Ð6Ð6°Ð6Ñ6Ô6Ñ	6Ô	6€BØ•+˜f r eÑ,Ô,­{¸6ÀBÀ5Ñ/IÔ/IÐIÔJÐJr   c                 ó  — t          | j        ¦  «        t          | j        ¦  «        t          | j        ¦  «        t          | j        ¦  «        f\  }}}}|D ](\  }}||cxk    r|k     rn Œ||cxk    r|k     rn Œ% dS Œ)dS )zJWhether any midpoint of the row band lies in rect (half-open, as extract).TF)rq   r    r   r1   r2   )rr   r¿   r    r   r1   r2   r™   r˜   s           r   rµ   rµ   A  s›   € å˜4œ7‘^”^¥U¨4¬7¡^¤^µU¸4¼7±^´^ÅUÈ4Ì7Á^Ä^ÐS�N€BˆˆB�Øð ð ‰ˆˆuØ�ÐÐÒÐ˜ÒÐÐÐÐ  eÐ 0Ð 0Ò 0Ð 0¨bÒ 0Ð 0Ð 0Ð 0Ð 0Ø�4�4øØˆ5r   c                 óL  — g }| j         pg D ]—}t          |t          ¦  «        sŒ|                     d¦  «        }|sŒ0	 t	          j        |dd…         ¦  «        }n# t          t          f$ r Y Œaw xY w|j        rŒm| 	                    |                     d¦  «        |f¦  «         Œ˜|S )zKThe page's layout groups as ``(class_name, rect)``, skipping unusable ones.r   Nr!   r   )
r"   r#   r$   r%   r+   r,   r”   r•   rQ   r*   )r-   r]   r/   r   rr   s        r   Ú_union_layout_groupsrÉ   J  sÊ   € à€FØÔ)Ð/¨Rð 7ð 7ˆÝ˜%¥Ñ&Ô&ð 	ØØ—Y’Y˜|Ñ,Ô,ˆ
Øð 	Øð	Ý”< 
¨2¨A¨2¤Ñ/Ô/ˆDˆDøÝ�:Ð&ð 	ð 	ð 	ØˆHð	øøøàŒ=ð 	ØØ�Š�u—y’y Ñ.Ô.°Ð5Ñ6Ô6Ð6Ð6Ø€Ms   ½AÁA.Á-A.c                 óÖ   — t          |¦  «        }|dk    rdS t          |z  }t          | ¦  «        D ]7\  }}|dk    rŒt          ||¦  «        |k     rŒ!|t          |¦  «        k    rŒ5 dS dS )a�  Whether a candidate sits inside a layout picture group without covering it.

    The layout model classified that region as a picture, so a line grid found
    almost entirely inside one is as likely to be a chart's gridlines as a table,
    and overriding the model's verdict needs table-shaped text. The shape, not the
    amount, is what tells them apart: a chart's text sits along its two axes, so
    exactly one row and one column are well filled and its partial gridlines leave
    most of the grid without a cell at all, while a table has a header row and a
    label column that are each at least half full over mostly complete cell
    coverage -- which a sparse matrix of scattered marks still satisfies. See the
    admission rule in _union_line_candidates.

    A candidate larger than the picture contains it instead -- a bordered table
    with an image in one of its cells -- and keeps the ordinary rule.
    r   FÚpictureT)rs   Ú_UNION_PICTURE_CONTAINMENTrÉ   rw   )r-   r~   r€   Ú	thresholdr   rr   s         r   rS   rS   ]  s�   € õ  & nÑ5Ô5€NØ˜ÒÐØˆuÝ*¨^Ñ;€IÝ0°Ñ6Ô6ð ð Ñˆ
�DØ˜Ò"Ð"ØÝ# N°DÑ9Ô9¸IÒEÐEØØÕ,¨TÑ2Ô2Ò2Ð2ØØˆtˆtØˆ5r   c                 ó@  — t          | dd¦  «        }|�|S g }|                      d¦  «                             dg ¦  «        pg D ]·}|                     dg ¦  «        pg D ]œ}|                     dg ¦  «        pg D ]�}t          |                     d¦  «        pd¦  «                             ¦   «         sŒ9|                     d	¦  «        }|sŒQt          j        |¦  «        }|j        s|                     |¦  «         Œ‚Œ�Œ¸	 t          | d|¦  «         n# t          $ r Y nw xY w|S )
z�Non-empty page text-span rects, cached on the page.

    Drives the grid-ref span-multiplicity gate: every non-blank span as a bare
    rect.Ú_union_text_spans_cacheNr$   ÚblocksÚlinesÚspansrŒ   r�   ra   )ÚgetattrÚget_textr%   r‘   r’   r+   r,   rQ   r*   ÚsetattrÚ	Exception)r-   ÚcachedrÒ   ÚblockÚlineÚspanra   rr   s           r   Ú_union_text_span_rectsrÛ   |  s\  € õ
 �TÐ4°dÑ;Ô;€FØÐØˆØ€EØ—’˜vÑ&Ô&×*Ò*¨8°RÑ8Ô8Ð>¸Bð 
'ð 
'ˆØ—I’I˜g rÑ*Ô*Ð0¨bð 		'ð 		'ˆDØŸš ¨"Ñ-Ô-Ð3°ð 'ð '�Ý˜4Ÿ8š8 FÑ+Ô+Ð1¨rÑ2Ô2×8Ò8Ñ:Ô:ð ØØ—x’x Ñ'Ô'�Øð ØÝ”| DÑ)Ô)�Ø”}ð 'Ø—L’L Ñ&Ô&Ð&øð'ð		'ðÝ�Ð/°Ñ7Ô7Ð7Ð7øÝð ð ð Øˆðøøøà€Ls   Ã<D Ä
DÄDc                 ón  — g }|D �]X}t          |j        ¦  «        t          |j        ¦  «        z   dz  }|t          | j        ¦  «        dz
  k     s|t          | j        ¦  «        dz   k    rŒft          || ¦  «        dk    rŒ{t	          t          | j        ¦  «        t          |j        ¦  «        ¦  «        }t          t          | j        ¦  «        t          |j        ¦  «        ¦  «        }||k    rŒêt          |¦  «        D ]D\  }\  }}	t          ||z
  ¦  «        dk    r&|	 
                    ||f¦  «         ||z   dz  |	f||<    nŒE| 
                    |||fgf¦  «         �ŒZd}
|D ]Q\  }}	d}d}t          |	¦  «        D ](\  }}|�	||z
  dk    r|dz  }|}Œt	          ||¦  «        }Œ)t	          |
|¦  «        }
ŒR|
S )zNMax horizontally-separated text-span groups on any single text line in a cell.rŽ   g      ð?g      @r   Nr   )rq   r   r2   ry   rP   r    rO   r1   r{   Úabsr*   r³   )r@   Ú
text_spansÚ
line_bandsrÚ   Úcenter_yr    r1   r„   Úband_yÚ	intervalsÚbestÚ_r]   Úlast_x1s                 r   Ú_union_cell_span_group_countræ   —  sæ  € à€JØð 6ñ 6ˆÝ˜$œ'‘N”N¥U¨4¬7¡^¤^Ñ3°sÑ:ˆØ•e˜DœG‘n”n sÑ*Ò*Ð*¨h½¸t¼w¹¼È#Ñ9MÒ.MÐ.MØÝ˜D $Ñ'Ô'¨3Ò.Ð.ØÝ•�t”w‘”¥ t¤w¡¤Ñ0Ô0ˆÝ•�t”w‘”¥ t¤w¡¤Ñ0Ô0ˆØ�Š8ˆ8ØÝ*3°JÑ*?Ô*?ð 	6ð 	6Ñ&ˆEÑ&�F˜IÝ�8˜fÑ$Ñ%Ô%¨Ò,Ð,Ø× Ò  " b Ñ*Ô*Ð*Ø&,¨xÑ&7¸3Ñ%>À	Ð$J�
˜5Ñ!Ø�ð -ð
 ×Ò˜x¨2¨r¨(¨Ð4Ñ5Ô5Ð5ùØ€DØ"ð 	!ð 	!‰ˆˆ9ØˆØˆÝ˜YÑ'Ô'ð 	+ð 	+‰FˆB�Øˆ " w¡,°Ò"4Ð"4Ø˜!‘�Ø��å˜g rÑ*Ô*��Ý�4˜Ñ Ô ˆˆØ€Kr   c                 óø   — | €dS t          | ¦  «        }d}|D ]P}|D ]K}|€Œt          j        |¦  «        }|j        rŒ!t	          ||¦  «        }|dk    r|€|nt          ||¦  «        }ŒLŒQ|�t          |¦  «        ndS )zEMax cell span-group count over a grid (high => under-segmented grid).Nr   )rÛ   r+   r,   rQ   ræ   rP   rq   )r-   r3   rÞ   rã   r5   r@   rr   Úcounts           r   Ú_union_span_multiplicityré   ¹  s±   € à€|ØˆtÝ'¨Ñ-Ô-€JØ€DØð 	Cð 	CˆØð 	Cð 	CˆDØˆ|ØÝ”< Ñ%Ô%ˆDØŒ}ð ØÝ0°°zÑBÔBˆEØ�qŠyˆyØ $ �u�uµ#°d¸EÑ2BÔ2B�øð	Cð Ð*�5�‰;Œ;ˆ;°Ð4r   c                óî  — i }i }t          | ¦  «        D ]¦\  }\  }	}
t          |¦  «        D ]Ž\  }\  }}t          |	|¦  «        }||k    rp|                     |g ¦  «                             |t	          |¦  «        f¦  «         |                     |g ¦  «                             |t	          |¦  «        f¦  «         Œ�Œ§i }t          ¦   «         }|                     ¦   «         D ]“\  }}t          |¦  «        dk    rŒ|d         \  }}t          |                     |g ¦  «        ¦  «        dk    rŒL|r%t          |||         d         ¦  «        }|�||k    rŒs||         ||<   | 
                    |¦  «         Œ”||fS )a]  Primaries a candidate can grid-ref (replace grid with), 1:1 by IoU.

    ``existing``/``candidates`` are ``(bbox, grid)`` lists. Returns ``(refs,
    consumed)``: ``refs`` maps a primary index to the candidate supplying its
    grid (mutual 1:1 IoU>=threshold matches passing the span-multiplicity gate),
    ``consumed`` the candidate indexes used.r   r   )r{   r
   Ú
setdefaultr*   rq   rN   Úitemsr)   r%   ré   r[   )Úexistingrd   Úiou_thresholdr-   Úspan_mult_gateÚspan_mult_thresholdÚexisting_matchesÚcandidate_matchesÚexisting_indexr…   Ú_gridÚcandidate_indexr~   Ú_cgridÚiouÚrefsÚconsumedÚmatchesrä   Ú	span_mults                       r   Ú_union_one_to_one_grid_refsrü   Ì  sº  € ð ÐØÐÝ2;¸HÑ2EÔ2Eð gð gÑ.ˆÑ.˜¨Ý9BÀ:Ñ9NÔ9Nð 	gð 	gÑ5ˆOÑ5˜n¨fÝ�} nÑ5Ô5ˆCØ�mÒ#Ð#Ø ×+Ò+¨N¸BÑ?Ô?×FÒFÈÕY^Ð_bÑYcÔYcÐGdÑeÔeÐeØ!×,Ò,¨_¸bÑAÔA×HÒHÈ.ÕZ_Ð`cÑZdÔZdÐIeÑfÔfÐføð		gð
 €DÝ‰uŒu€HØ#3×#9Ò#9Ñ#;Ô#;ð &ð &Ñˆ˜Ýˆw‰<Œ<˜1ÒÐØØ$ QœZÑˆ˜ÝÐ ×$Ò$ _°bÑ9Ô9Ñ:Ô:¸aÒ?Ð?ØØð 	Ý0°°zÀ/Ô7RÐSTÔ7UÑVÔVˆIØÐ$¨Ð6IÒ)IÐ)IØØ)¨/Ô:ˆˆ^ÑØ�Š�_Ñ%Ô%Ð%Ð%Ø�ˆ>Ðr   c                óÄ  — d„ | D ¦   «         }|rt          | |||||¬¦  «        \  }}	ni t          ¦   «         }	}i }
g }t          |¦  «        D ]g\  }}||	v rŒ
t          |d         |¦  «        \  }}|�*|
                     |g ¦  «                             |¦  «         ŒO|rŒR|                     |¦  «         Œhd„ |
                     ¦   «         D ¦   «         }g }t          | ¦  «        D ]h\  }}||v r|                     ||         ¦  «         Œ%||v r*|                     |d         ||         d         f¦  «         ŒS|                     |¦  «         Œi|                     |¦  «         |S )a  Fuse primary and candidate ``(bbox, grid)`` entries.

    Applies grid-ref replacement, split replacement (>=2 candidates owned by one
    primary replace it, ordered by y0/x0) and append of unowned candidates,
    returning the fused entry list in the contractual order.c                 ó   — g | ]
}|d          ‘ŒS )r   r   )r   Úentrys     r   r   z)_union_replace_append.<locals>.<listcomp>ò  s   € Ð6Ð6Ð6 E�u˜Q”xÐ6Ð6Ð6r   )rî   r-   rï   rð   r   Nc                 ó`   — i | ]+\  }}t          |¦  «        d k    ¯|t          |d„ ¬¦  «        “Œ,S )r   c                 ój   — t          | d         j        ¦  «        t          | d         j        ¦  «        fS rœ   )rq   r   r    )rÿ   s    r   ú<lambda>z2_union_replace_append.<locals>.<dictcomp>.<lambda>  s(   € µ°e¸A´h´kÑ0BÔ0BÅEÈ%ÐPQÌ(Ì+ÑDVÔDVÐ/W€ r   )rb   )r)   r³   )r   r„   rì   s      r   ú
<dictcomp>z)_union_replace_append.<locals>.<dictcomp>
  sF   € ð ð ð áˆE�5Ýˆu‰:Œ:˜Š?ˆ?ð 	�v�eÐ!WÐ!WÐXÑXÔXàˆ?ˆ?r   r   )rü   rN   r{   rŠ   rë   r*   rì   Úextend)rí   rd   r-   Úgrid_refÚgrid_ref_iourï   rð   r   Ú	grid_refsrù   ÚreplacementsÚappend_candidatesrõ   Ú	candidateÚowner_indexrƒ   Úfinal_replacementsÚentriesr„   rÿ   s                       r   Ú_union_replace_appendr  ì  sË  € ð 7Ð6¨XÐ6Ñ6Ô6€OØð 
(Ý9ØØØ&ØØ)Ø 3ð
ñ 
ô 
Ñˆ	�8�8ð !¥#¡%¤%�8ˆ	Ø€LØÐÝ&/°
Ñ&;Ô&;ð 	0ð 	0Ñ"ˆ˜Ø˜hÐ&Ð&ØÝ!2°9¸Q´<ÀÑ!QÔ!QÑˆ�YØÐ"Ø×#Ò# K°Ñ4Ô4×;Ò;¸IÑFÔFÐFÐFØð 	0Øà×$Ò$ YÑ/Ô/Ð/Ð/ðð à(×.Ò.Ñ0Ô0ðñ ô Ðð
 €GÝ! (Ñ+Ô+ð "ð "‰ˆˆuØÐ&Ð&Ð&Ø�NŠNÐ-¨eÔ4Ñ5Ô5Ð5Ð5Ø�iÐÐà�NŠN˜E !œH i°Ô&6°qÔ&9Ð:Ñ;Ô;Ð;Ð;à�NŠN˜5Ñ!Ô!Ð!Ð!Ø‡N‚NÐ$Ñ%Ô%Ð%Ø€Nr   c          	      óÊ  — | j         €|                      d¬¦  «         t          | ¦  «        }t          | ||¬¦  «        \  }}t	          ||| dt
          t          t          ¬¦  «        }|€5t          j	        ¦   «          t          j	        ¦   «          t          | ¦  «        }g }|D ]9\  }}	d„ |	D ¦   «         }
|
sŒ|                     t          | |
|¬¦  «        ¦  «         Œ:||_        |S )aé  Detect a page's tables by fusing layout grids with line-based candidates.

    Ensures the raw layout (computed only when page.layout_information is None,
    like the official use_layout path), reads primary grids, detects candidates
    (forwarding the caller's virtual lines / boxes to the nested finder), applies
    grid-ref / split / append, and returns a TableFinder whose .tables carry the
    fused grids in contractual order (grid-ref tables keep their explicit layout
    bbox).NT)Ú
return_rawr8   )r-   r  r  rï   rð   c                 ó    — g | ]}|D ]}|®|‘ŒŒS rK   r   r�   s      r   r   z&_find_tables_union.<locals>.<listcomp>>  s*   € ÐIÐIÐI˜°ÐIÐI¨¸Ð8H�Ð8HÐ8HÐ8HÐ8Hr   )ra   )r"   Ú
get_layoutr7   rm   r  Ú_UNION_GRID_REF_IOUÚ_UNION_GRID_REF_SPAN_MULT_GATEÚ#_UNION_GRID_REF_SPAN_MULT_THRESHOLDr   rk   r   r   r*   r   Útables)r-   r9   r:   Ú	primariesrd   rl   r  r  ra   r3   Úflats              r   Ú_find_tables_unionr    s  € ð ÔÐ&Ø�Š 4ˆÑ(Ô(Ð(Ý# DÑ)Ô)€IÝ/Ø˜	¨Yðñ ô Ñ€J�õ $ØØØØÝ(Ý5Ý?ðñ ô €Gð €~õ
 	Œ‰ŒˆÝŒ‰ŒˆÝ˜TÑ"Ô"ˆØ€FØð 4ð 4‰
ˆˆdØIÐI ÐIÑIÔIˆØð 	ØØ�Š•e˜D $¨TÐ2Ñ2Ô2Ñ3Ô3Ð3Ð3Ø€F„MØ€Mr   )'Ú__doc__Úbisectr   Úcollectionsr   r+   ri   r   r   r   r   r	   r
   rj   r  r  r  r|   r}   rÌ   r   r7   rm   rs   rw   ry   rŠ   rT   rU   r´   rµ   rÉ   rS   rÛ   ræ   ré   rü   r  r  r   r   r   ú<module>r     s  ððð ð< Ð Ð Ð Ð Ð Ø "Ð "Ð "Ð "Ð "Ð "à €€€à PÐ PÐ PÐ PÐ PÐ PÐ PÐ PÐ PÐ PÐ PÐ PÐ PÐ PÐ PÐ Pð" !€ØÐ Ø!%Ð Ø&)Ð #ØÐ Ø!%Ð Ø Ð ð �
ØÐHñô €ð
ð ð ðB /3¸dð Mð Mð Mð Mð Mð`Sð Sð Sð!ð !ð !ðað að að!ð !ð !ð6ð ð ð*Að Að AðHKð Kð Kðð ð ðð ð ð&ð ð ð>ð ð ð6ð ð ðD5ð 5ð 5ð&ð ð ð@-ð -ð -ð` +/¸$ð 'ð 'ð 'ð 'ð 'ð 'ð 'r   