ó
    �®žjço  ã                   óÐ   • S SK r S SKrS SKJr  S SKJrJrJr  S SKJ	r	  S SK
JrJr  S SKJr  S SKJrJrJr  \ R&                  " \5      r " S S	5      r " S
 S5      r " S S5      rg)é    N)Údefaultdict)ÚBoundingBoxÚDocItemLabelÚSize)ÚTextCell)ÚClusterÚPage)ÚBaseLayoutPostprocessorOptions)ÚBoundingBoxSpatialIndexÚhas_positive_areaÚordered_bounding_boxc                   óH   • \ rS rSrSrS rS rS rS\\	\
\	   4   4S jrSrg	)
Ú	UnionFindé   z:Efficient Union-Find data structure for grouping elements.c                 ót   • U Vs0 s H  o"U_M     snU l         [        R                  US5      U l        g s  snf )Nr   )ÚparentÚdictÚfromkeysÚrank)ÚselfÚelementsÚelems      Ú_/home/mande/repo/quber/.venv/lib/python3.13/site-packages/docling/utils/layout_postprocessor.pyÚ__init__ÚUnionFind.__init__   s1   € Ù.6Ó7ªh d˜T’z©hÑ7ˆŒÜ—M‘M (¨AÓ.ˆ�	ùò 8s   …5c                 óœ   • U R                   U   U:w  a+  U R                  U R                   U   5      U R                   U'   U R                   U   $ ©N)r   Úfind)r   Úxs     r   r   ÚUnionFind.find   s>   € Ø�;‰;�q‰>˜QÓØ!ŸY™Y t§{¡{°1¡~Ó6ˆD�K‰K˜‰NØ�{‰{˜1‰~Ðó    c                 óX  • U R                  U5      U R                  U5      pCX4:X  a  g U R                  U   U R                  U   :”  a  X0R                  U'   g U R                  U   U R                  U   :  a  X@R                  U'   g X0R                  U'   U R                  U==   S-  ss'   g )Né   )r   r   r   )r   r   ÚyÚroot_xÚroot_ys        r   ÚunionÚUnionFind.union"   sŽ   € ØŸ™ 1› t§y¡y°£|�ØÓØà�9‰9�VÑ˜tŸy™y¨Ñ0Ó0Ø"(�K‰K˜ÒØ�Y‰Y�vÑ §¡¨6Ñ!2Ó2Ø"(�K‰K˜Òà"(�K‰K˜ÑØ�I‰I�fÓ Ñ"Ôr!   Úreturnc                 óŽ   • [        [        5      nU R                   H%  nXR                  U5         R	                  U5        M'     U$ )z%Returns groups as {root: [elements]}.)r   Úlistr   r   Úappend)r   Úgroupsr   s      r   Ú
get_groupsÚUnionFind.get_groups/   s8   € äœTÓ"ˆØ—K”KˆDØ—9‘9˜T“?Ñ#×*Ñ*¨4Ö0ñ  àˆr!   )r   r   N)Ú__name__Ú
__module__Ú__qualname__Ú__firstlineno__Ú__doc__r   r   r'   r   Úintr+   r.   Ú__static_attributes__© r!   r   r   r      s-   † ÙDò/òò
#ð˜D  d¨3¡i Ñ0÷ r!   r   c            
       ó~   • \ rS rSrSrS\\   4S jrS\4S jrS\4S jr	S\
S	\\   4S
 jrS\
S\
S\S\S	\4
S jrSrg)ÚSpatialClusterIndexé7   z8Efficient spatial indexing for clusters using an R-tree.Úclustersc                 ód   • [        5       U l        0 U l        U H  nU R                  U5        M     g r   )r   Úspatial_indexÚclusters_by_idÚadd_cluster)r   r;   Úclusters      r   r   ÚSpatialClusterIndex.__init__:   s-   € Ü4Ó6ˆÔØ24ˆÔãˆGØ×Ñ˜WÖ%ò  r!   r@   c                 ó”   • U R                   R                  UR                  UR                  5        XR                  UR                  '   g r   )r=   ÚinsertÚidÚbboxr>   ©r   r@   s     r   r?   ÚSpatialClusterIndex.add_clusterA   s2   € Ø×Ñ×!Ñ! '§*¡*¨g¯l©lÔ;Ø*1×Ñ˜GŸJ™JÒ'r!   c                 ó’   • U R                   R                  UR                  UR                  5        U R                  UR                  	 g r   )r=   ÚdeleterD   rE   r>   rF   s     r   Úremove_clusterÚ"SpatialClusterIndex.remove_clusterE   s2   € Ø×Ñ×!Ñ! '§*¡*¨g¯l©lÔ;Ø×Ñ §
¡
Ñ+r!   rE   r)   c                 óJ   • [        U R                  R                  U5      5      $ )aM  Find cluster IDs whose bbox intersects ``bbox``.

Every relation ``check_overlap`` accepts -- IoU or either containment
ratio above a positive threshold -- requires a positive intersection
area, so the R-tree query is already a superset of the pairs that can
survive. Widening it further only adds candidates that are then
rejected.
)Úsetr=   Úintersection)r   rE   s     r   Úfind_candidatesÚ#SpatialClusterIndex.find_candidatesI   s    € ô �4×%Ñ%×2Ñ2°4Ó8Ó9Ð9r!   Úbbox1Úbbox2Úoverlap_thresholdÚcontainment_thresholdc                 ó
  • [        U5      n[        U5      n[        U5      (       a  [        U5      (       d  gUR                  U5      nUR                  U5      nUR                  U5      nXS:„  =(       d    Xd:„  =(       d    Xt:„  $ )z)Check if two bboxes overlap sufficiently.F)r   r   Úintersection_over_unionÚintersection_over_self)r   rQ   rR   rS   rT   ÚiouÚcontainment1Úcontainment2s           r   Úcheck_overlapÚ!SpatialClusterIndex.check_overlapT   s„   € ô % UÓ+ˆÜ$ UÓ+ˆÜ  ×'Ñ'Ô/@À×/GÑ/GØà×+Ñ+¨EÓ2ˆØ×3Ñ3°EÓ:ˆØ×3Ñ3°EÓ:ˆð Ñ#÷ 4ØÑ3÷4àÑ3ð	
r!   )r>   r=   N)r0   r1   r2   r3   r4   r+   r   r   r?   rJ   r   rM   r5   rO   ÚfloatÚboolr[   r6   r7   r!   r   r9   r9   7   sy   † ÙBð&  g¡ô &ð2 7ô 2ð, gô ,ð	: Kð 	:°C¸±Hô 	:ð
àð
ð ð
ð !ð	
ð
  %ð
ð 
÷
r!   r9   c                   óü  • \ rS rSrSrSSS.SSS.SSS.S	.r\R                  \R                  1r	\R                  \R                  1r\	R                  \5      r\R                  \R                  15      r0 \R"                  S
_\R$                  S
_\R&                  S
_\R(                  S
_\R*                  S
_\R,                  S
_\R                  S
_\R.                  S_\R                  S
_\R0                  S
_\R2                  S_\R4                  S_\R6                  S_\R8                  S_\R                  S_\R                  S_\R                  S_r\R2                  \R.                  0rS\S\ \!   S\"SS4S jr#S\ \!   4S jr$S\ \!   4S jr%S\ \!   4S jr&S\!S\ \!   SS4S jr'\(  S5S\ \!   S\ \!   S\)S\)S\*\+   4
S jj5       r,S\ \!   4S jr-S\!S\!S \.S\/4S! jr0S"\ \!   S \.S\!4S# jr1  S6S\ \!   S$\2S%\)S&\)S\ \!   4
S' jjr3S\ \!   S(\)S)\)S\!4S* jr4S+\ \5   S\ \5   4S, jr6 S7S\ \!   S-\)S\ \!   4S. jjr7S\ \!   S\ \5   4S/ jr8S\ \!   S\ \!   4S0 jr9S+\ \5   S\ \5   4S1 jr: S8S\ \!   S2\2S\ \!   4S3 jjr;S4r<g)9ÚLayoutPostprocessorél   zKPostprocesses layout predictions by cleaning up clusters and mapping cells.gÍÌÌÌÌÌô?gš™™™™™©?)Úarea_thresholdÚconf_thresholdg       @g333333Ó?çš™™™™™É?)ÚregularÚpictureÚwrapperg      à?gÍÌÌÌÌÌÜ?Úpager;   Úoptionsr)   Nc                 ó´  • UR                   U l         Xl        UR                  U l        X l        X0l        U Vs/ s H   oDR                  U R                  ;  d  M  UPM"     snU l        U Vs/ s H   oDR                  U R                  ;   d  M  UPM"     snU l	        [        U R                  5      U l        [        U R                   Vs/ s H$  oDR                  [        R                  :X  d  M"  UPM&     sn5      U l        [        U R                   Vs/ s H   oDR                  U R                  ;   d  M  UPM"     sn5      U l        gs  snf s  snf s  snf s  snf )z,Initialize processor with page and clusters.N)Úcellsrh   ÚsizeÚ	page_sizeÚall_clustersri   ÚlabelÚSPECIAL_TYPESÚregular_clustersÚspecial_clustersr9   Úregular_indexr   ÚPICTUREÚpicture_indexÚWRAPPER_TYPESÚwrapper_index)r   rh   r;   ri   Úcs        r   r   ÚLayoutPostprocessor.__init__š   s  € ð —Z‘ZˆŒ
ØŒ	ØŸ™ˆŒØ$ÔØŒáó!
Ú�!§7¡7°$×2DÑ2DÑ#D�A‘xñ!
ˆÔñ -5Ó VªH q¿¹À4×CUÑCUÑ8U§©HÑ VˆÔô 1°×1FÑ1FÓGˆÔÜ0Ø×-Ò-ÓQÒ-�1·±¼L×<PÑ<PÑ1P�QÑ-ÑQó
ˆÔô 1Ø×-Ò-ÓOÒ-�1·±¸D×<NÑ<NÑ1N�QÑ-ÑOó
ˆÕùò!
ùò !Wùò
 Rùò Ps/   ¹EÁEÁ,EÂEÃ!EÃ-EÄEÄ3Ec                 óØ  • U R                  5       U l        U R                  5       U l        U R                   VVs1 s H]  nUR                  U R
                  ;   d   UR                  [        R                  :X  d  M=  UR                    H  nUR                  iM     M_     nnnU R                   Vs/ s H  oDR                  U;  d  M  UPM     snU l        U R                  U R                  U R                  -   SS9nU R                  R                  (       dÉ  U HV  nU R                  UR                  5      Ul        UR                   H#  nU R                  UR                  5      Ul        M%     MX     U R                  R                   bV  U R                  U R                  R                   l        [%        U R                  5      S:„  U R                  R                   l        U$ s  snnf s  snf )zMain processing pipeline.rD   ©Úmoder   )Ú_process_regular_clustersrq   Ú_process_special_clustersrr   ro   ÚTABLE_TYPESr   rt   ÚchildrenrD   Ú_sort_clustersri   Úskip_cell_assignmentÚ_sort_cellsrk   rh   Úparsed_pageÚtextline_cellsÚlenÚ	has_lines)r   rg   ÚchildÚcontained_idsrx   Úfinal_clustersr@   s          r   ÚpostprocessÚLayoutPostprocessor.postprocessµ   s—  € à $× >Ñ >Ó @ˆÔØ $× >Ñ >Ó @ˆÔð
  ×0Ò0ô
â0�Ø�}‰} × 0Ñ 0Ó0Ø�}‰}¤× 4Ñ 4Ñ4ó ð !×)Õ)�ð	 �HŒHñ *ñ	 Ù0ð 	ñ 
ð ×,Ò,ó!
Ú,�!·±¸MÑ0I�AÑ,ñ!
ˆÔð
 ×,Ñ,Ø×!Ñ! D×$9Ñ$9Ñ9Àð -ð 
ˆð
 �|‰|×0×0Û)�Ø $× 0Ñ 0°·±Ó ?�”à$×-Ô-�EØ"&×"2Ñ"2°5·;±;Ó"?�E–Kó .ñ *ð �y‰y×$Ñ$Ñ0Ø7;·z±z�—	‘	×%Ñ%Ô4Ü25°d·j±j³/ÀAÑ2E�—	‘	×%Ñ%Ô/àÐùó?
ùò!
s   º<G!Á:$G!Â/G'ÃG'c                 ó~  • U R                    Vs/ s H.  nUR                  U R                  UR                     :¼  d  M,  UPM0     nnU H=  nUR                  U R                  ;   d  M  U R                  UR                     Ul        M?     U R
                  R                  (       Gd.  U R                  U5      nU R
                  R                  (       dC  U Vs/ s H6  nUR                  (       d   UR                  [        R                  :X  d  M4  UPM8     nnU R                  U5      nU(       a§  U R
                  R                  (       aŒ  [        S U R                   5       SS9S-   n/ n[!        U5       HL  u  pxUR                  n	UR#                  [%        XW-   [        R&                  UR)                  5       U	U/S95        MN     UR+                  U5        [-        U5      S-   n
[/        S5       HC  nU
[-        U5      :X  a    U$ [-        U5      n
U R1                  U5      nU R3                  US5      nME     U$ s  snf s  snf )z3Process regular clusters with iterative refinement.c              3   ó8   #   • U  H  oR                   v •  M     g 7fr   ©rD   )Ú.0rx   s     r   Ú	<genexpr>Ú@LayoutPostprocessor._process_regular_clusters.<locals>.<genexpr>û   s   é € Ð?Ò->¨ŸtžtÒ->ùó   ‚r   )Údefaultr#   )rD   ro   rE   Ú
confidencerk   é   re   )rq   r•   ÚCONFIDENCE_THRESHOLDSro   ÚLABEL_REMAPPINGri   r‚   Ú_assign_cells_to_clustersÚkeep_empty_clustersrk   r   ÚFORMULAÚ_find_unassigned_cellsÚcreate_orphan_clustersÚmaxrn   Ú	enumerater,   r   ÚTEXTÚto_bounding_boxÚextendr†   ÚrangeÚ_adjust_cluster_bboxesÚ_remove_overlapping_clusters)r   rx   r;   r@   Ú
unassignedÚnext_idÚorphan_clustersÚiÚcellÚconfÚ
prev_countÚ_s               r   r}   Ú-LayoutPostprocessor._process_regular_clustersÜ   sú  € ð ×*Ò*ó
â*�Ø�|‰|˜t×9Ñ9¸!¿'¹'ÑBÑB÷ Ù*ð 	ð 
ó  ˆGØ�}‰} × 4Ñ 4Õ4Ø $× 4Ñ 4°W·]±]Ñ C�–ñ  ð
 �|‰|×0×0Ð0à×5Ñ5°hÓ?ˆHð —<‘<×3×3ñ $,óâ#+˜Ø—}—}¨¯©¼×9MÑ9MÑ(M÷ Ù#+ð ð ð ×4Ñ4°XÓ>ˆJÞ˜dŸl™l×A×AÜÑ?¨T×->Ò->Ó?ÈÑKÈaÑO�Ø"$�Ü(¨Ö4‘G�AØŸ?™?�Dà#×*Ñ*ÜØ&™{Ü".×"3Ñ"3Ø!%×!5Ñ!5Ó!7Ø'+Ø#' &ñöñ  5ð —‘ Ô0ô ˜“] QÑ&ˆ
Ü�q–ˆAØœS ›]Ó*Øð
 ˆô	 ˜X›ˆJØ×2Ñ2°8Ó<ˆHØ×8Ñ8¸À9ÓMŠHñ ð ˆùòm
ùò&s   �+H5¾H5Ã3H:ÄH:c                 ó’	  • U R                    Vs/ s H.  nUR                  U R                  UR                     :¼  d  M,  UPM0     nnU R                  c   eU R                  R
                  U R                  R                  -  nUS:”  aS  U Vs/ s HF  nUR                  [        R                  :X  a#  UR                  R                  5       U-  S:”  a  MD  UPMH     nnU Vs/ s H$  oR                  [        R                  :X  d  M"  UPM&     nnU R                  US5      nU Vs/ s H   oR                  U R                  ;   d  M  UPM"     nnU R                  US5      nU Vs/ s H   oR                  U R                  ;   d  M  UPM"     nnU R                  US5      nU R                  XV-   U-   5      nU Vs/ s H%  nUR                  [        R                  :X  d  M#  UPM'     nnU Vs/ s H   oDR                  U R                  ;   d  M  UPM"     nnU Vs/ s H!  nUR                  U R                  ;   d  M  UPM#     nnXe-   nU H[  nU R                   V	s/ s H0  n	U	R                  R!                  UR                  5      S:”  d  M.  U	PM2     n
n	U R#                  XJ5        M]     0 nU Hl  nU Vs/ s H0  nUR                  R!                  UR                  5      S:”  d  M.  UPM2     nnU(       d  MI  [%        US S9nUR&                  X¼R&                  '   Mn     U VV	s1 s H!  oÌR(                    H  o™R&                  iM     M#     nnn	0 nU R                   H  nUR&                  U;   a  M  U Vs/ s H0  nUR                  R!                  UR                  5      S:”  d  M.  UPM2     nnU(       d  M[  [%        US S9nUR&                  UUR&                  '   M�     U Hœ  nU Vs/ s H0  nUR+                  UR&                  5      UR&                  :X  d  M.  UPM2     nnU R                   V	s/ s H0  n	UR+                  U	R&                  5      UR&                  :X  d  M.  U	PM2     nn	U R#                  UUU-   5        Mž     XV-   U-   $ s  snf s  snf s  snf s  snf s  snf s  snf s  snf s  snf s  sn	f s  snf s  sn	nf s  snf s  snf s  sn	f )	Nr   gÍÌÌÌÌÌì?rf   rg   çš™™™™™é?c                 óf   • U R                   R                  5       U R                  * U R                  4$ r   ©rE   Úarear•   rD   ©Ú	containers    r   Ú<lambda>Ú?LayoutPostprocessor._process_special_clusters.<locals>.<lambda>`  ó*   € Ø!Ÿ™×+Ñ+Ó-Ø"×-Ñ-Ð-Ø!Ÿ™ñ+r!   ©Úkeyc                 óf   • U R                   R                  5       U R                  * U R                  4$ r   r²   r´   s    r   r¶   r·   w  r¸   r!   )rr   r•   r—   ro   rm   ÚwidthÚheightr   rt   rE   r³   r¥   r   ÚCONTAINER_TYPESÚ_handle_cross_type_overlapsrq   rW   Ú_set_cluster_childrenÚminrD   r€   Úget)r   rx   rr   Ú	page_arear@   Úpicture_clustersÚtable_clustersÚcontainer_clustersÚnested_clustersre   r€   Úparent_by_child_idrˆ   rµ   Úparentsr   Únested_regular_idsÚparent_by_regular_idÚnested_childrenÚdirect_childrens                       r   r~   Ú-LayoutPostprocessor._process_special_clusters  sß  € ð ×*Ò*ó
â*�Ø�|‰|˜t×9Ñ9¸!¿'¹'ÑBÑB÷ Ù*ð 	ð 
ð �~‰~Ñ)Ð)Ð)Ø—N‘N×(Ñ(¨4¯>©>×+@Ñ+@Ñ@ˆ	Ø�q‹=ñ  0ó â/�Gà—M‘M¤\×%9Ñ%9Ó9ØŸ™×)Ñ)Ó+¨iÑ7¸$Ñ>÷	 Ù/ð ð  ñ (ó
Ú'�!¯7©7´l×6JÑ6JÑ+J�AÑ'ð 	ð 
ð  ×<Ñ<Ø˜ió
Ðñ &6ÓUÒ%5 ¿¹ÀD×DTÑDTÑ9TŸ!Ñ%5ˆÐUØ×:Ñ:¸>È9ÓUˆñ (ó
Ú'�!¯7©7°d×6JÑ6JÑ+J�AÑ'ð 	ð 
ð "×>Ñ>Ø 	ó
Ðð  ×;Ñ;ØÑ-Ð0BÑBó
Ðñ
 ,ó
â+�Ø�}‰}¤× 4Ñ 4Ñ4÷ Ù+ð 	ð 
ñ $4ó
Ú#3˜·}±}È×HXÑHXÑ7X�GÑ#3ð 	ð 
ñ
 ,ó
â+�Ø�}‰} × 4Ñ 4Ñ4÷ Ù+ð 	ð 
ð )Ñ;ˆÛ&ˆGð  $×4Ò4óâ4�GØ—<‘<×6Ñ6°w·|±|ÓDÀsÑJ÷ Ù4ð ð ð
 ×&Ñ& wÖ9ñ 'ð  ÐÛ$ˆEñ "4óâ!3�IØ—:‘:×4Ñ4°Y·^±^ÓDÀsÑJ÷ Ù!3ð ð ÷
 ˆwÜØññ�ð 06¯y©yÐ"§8¡8Ó,ñ %ñ$ %4ô
Ú$3˜5Ç>Å>¸�JŒJÁ>‰J¡Oð 	ñ 
ð  "ÐØ×*Ô*ˆEØ�x‰xÐ-Ó-Ùñ "4óâ!3�IØ—:‘:×4Ñ4°Y·^±^ÓDÀsÑJ÷ Ù!3ð ð ÷
 ˆwÜØññ�ð 28·±Ð$ U§X¡XÓ.ñ# +ó& ,ˆIñ -óâ,�EØ%×)Ñ)¨%¯(©(Ó3°y·|±|ÑC÷ Ù,ð ð ð  $×4Ò4óâ4�GØ'×+Ñ+¨G¯J©JÓ7¸9¿<¹<ÑG÷ Ù4ð ð ð
 ×&Ñ& y°/ÀOÑ2SÖTñ ,ð  Ñ0Ð3EÑEÐEùòk
ùò ùò
ùò Vùò
ùò
ùò

ùò
ùòùòùó 
ùòùò"ùò
s¡   �+R¾RÂARÃRÃ!RÄRÄ"RÅRÅ!RÆRÆ6"RÇRÇ(R È	R ÈR%È7R%É-R*ÊR*Ê/-R/Ë R/Ì(R4Í/-R:Î R:Ï"-R?ÐR?Ð)-SÑSr@   r€   c           	      ó€  • U(       d  g U R                  USS9Ul        UR                  U R                  ;   ay  [	        [        S UR                   5       5      [        S UR                   5       5      [        S UR                   5       5      [        S UR                   5       5      S9Ul        U R                  R                  (       df  U R                  UR                   VVs/ s H  o3R                    H  oDPM     M     snn5      Ul        U R                  UR                  5      Ul        g / Ul        g s  snnf )NrD   r{   c              3   óL   #   • U  H  oR                   R                  v •  M     g 7fr   )rE   Úl©r�   rˆ   s     r   r‘   Ú<LayoutPostprocessor._set_cluster_children.<locals>.<genexpr>–  ó   é € ÐAÒ0@ u—j‘j—l–lÒ0@ùó   ‚"$c              3   óL   #   • U  H  oR                   R                  v •  M     g 7fr   )rE   ÚtrÒ   s     r   r‘   rÓ   —  rÔ   rÕ   c              3   óL   #   • U  H  oR                   R                  v •  M     g 7fr   )rE   ÚrrÒ   s     r   r‘   rÓ   ˜  rÔ   rÕ   c              3   óL   #   • U  H  oR                   R                  v •  M     g 7fr   )rE   ÚbrÒ   s     r   r‘   rÓ   ™  rÔ   rÕ   ©rÑ   r×   rÙ   rÛ   )r�   r€   ro   r¾   r   rÁ   rž   rE   ri   r‚   Ú_deduplicate_cellsrk   rƒ   )r   r@   r€   rˆ   rª   s        r   rÀ   Ú)LayoutPostprocessor._set_cluster_childrenŽ  sø   € ÞØà×.Ñ.¨x¸dÐ.ÐCˆÔà�=‰=˜D×0Ñ0Ó0Ü&ÜÑA°×0@Ò0@ÓAÓAÜÑA°×0@Ò0@ÓAÓAÜÑA°×0@Ò0@ÓAÓAÜÑA°×0@Ò0@ÓAÓAñ	ˆGŒLð �|‰|×0×0Ø ×3Ñ3Ø#*×#3Ò#3ÔLÒ#3˜%ÇÅ¸’Á‘Ñ#3ÒLóˆGŒMð !×,Ñ,¨W¯]©]Ó;ˆG�MàˆG�Mùó	 Ms   Ã&D:
ÚlosersÚwinnersÚiou_thresholdÚconf_tolerancec                 ó
  • [        5       nU  Hr  nU Hi  nUR                  R                  UR                  5      U::  a  M.  UR                  UR                  -
  U:  d  MM  UR	                  UR
                  5          Mp     Mt     U$ )aÃ  Elect a winner for near-identical (loser, winner) label pairs.

For each pair whose bboxes are near-identical (``IoU > iou_threshold``)
AND whose confidences are within ``conf_tolerance`` of each other, the
loser label is dropped so the winner label survives. Nothing else --
containment, area, downstream behaviour -- is considered.

Pairs outside this envelope (low IoU, or a clearly more confident
loser) are left alone for other passes to handle.
)rM   rE   rV   r•   ÚaddrD   )rß   rà   rá   râ   Úto_dropÚloserÚwinners          r   Ú_resolve_coincident_pairsÚ-LayoutPostprocessor._resolve_coincident_pairs¤  sp   € ô"  ›EˆÛˆEÛ!�Ø—:‘:×5Ñ5°f·k±kÓBÀmÓSÙØ×$Ñ$ v×'8Ñ'8Ñ8¸NÕJØ—K‘K §¡Ô)Úó "ñ ð ˆr!   c                 óâ  • U Vs/ s H$  o"R                   [        R                  :X  d  M"  UPM&     nnU Vs/ s H$  o"R                   [        R                  :X  d  M"  UPM&     nnU Vs/ s H$  o"R                   [        R                  :X  d  M"  UPM&     nnU Vs/ s H   o"R                   U R
                  ;   d  M  UPM"     nn[        5       nXpR                  X45      -  nXpR                  XSU-   5      -  nX4-   U-    Vs/ s H  o"R                  U;  d  M  UPM     nnXpR                  Xh5      -  nU Vs/ s H  o"R                  U;  d  M  UPM     sn$ s  snf s  snf s  snf s  snf s  snf s  snf )aÎ  Elect a winner for cross-type label pairs at near-identical bboxes.

The layout model can emit the same grounded region under several
labels. When two labels sit at near-identical bboxes with similar
confidence, this step picks the label carrying the richer downstream
semantic. Anything outside that envelope is out of scope here.

| pair                                | loser     | winner                 |
|-------------------------------------|-----------|------------------------|
| TABLE vs DOCUMENT_INDEX             | TABLE     | DOCUMENT_INDEX         |
| PICTURE vs TABLE / DOC_INDEX        | PICTURE   | TABLE / DOCUMENT_INDEX |
| FORM / KVR vs TABLE / DOC / PICTURE | container | structured element     |
)	ro   r   ÚTABLEÚDOCUMENT_INDEXrt   r¾   rM   rè   rD   )	r   rr   rx   ÚtablesÚdoc_indicesÚpicturesÚ
containersÚclusters_to_removeÚsurviving_structureds	            r   r¿   Ú/LayoutPostprocessor._handle_cross_type_overlaps¿  si  € ñ .ÓOÒ-˜·±¼L×<NÑ<NÑ1N—!Ñ-ˆÐOá'ó
Ú'�!¯7©7´l×6QÑ6QÑ+Q�AÑ'ð 	ð 
ñ  0ÓSÒ/˜!·7±7¼l×>RÑ>RÑ3R—AÑ/ˆÐSÙ!1ÓUÒ!1˜A·W±WÀ×@TÑ@TÑ5T—aÑ!1ˆ
ÐUä'*£uÐØ×<Ñ<¸VÓQÑQÐØ×<Ñ<Ø˜{Ñ*ó
ñ 	
Ðð Ñ+¨hÒ6ó 
Ú6�!¿$¹$ÐFXÑ:X�AÑ6ð 	ð  
ð 	×<Ñ<Øó
ñ 	
Ðñ ,ÓNÒ+�a¯t©tÐ;MÑ/M—Ñ+ÑNÐNùò' Pùò
ùò TùÚUùò 
ùò OsE   …!EªE¶!EÁEÁ'!EÂEÂE"Â9E"Ã=E'ÄE'Ä3E,Å
E,Ú	candidateÚotherÚparamsc                 ój  • UR                   [        R                  :X  al  UR                   [        R                  :X  aN  UR                  R                  5       UR                  R                  5       -  n[        SU-
  5      S:  nU(       a  gUR                   [        R                  :X  a,  UR                  R                  UR                  5      nUS:”  a  gUR                  R                  5       UR                  R                  5       -  nUR                  UR                  -
  nXCS   ::  a	  XsS   :”  a  gg)z’Determine if candidate cluster should be preferred over other cluster based on rules.
Returns True if candidate should be preferred, False if not.r#   rd   Tr°   rb   rc   F)
ro   r   Ú	LIST_ITEMr    rE   r³   ÚabsÚCODErW   r•   )r   rô   rõ   rö   Ú
area_ratioÚarea_similarityÚcontainmentÚ	conf_diffs           r   Ú_should_prefer_clusterÚ*LayoutPostprocessor._should_prefer_clusterâ  sö   € ð �O‰Oœ|×5Ñ5Ó5Ø—‘œ|×0Ñ0Ó0ð #Ÿ™×,Ñ,Ó.°·±·±Ó1BÑBˆJÜ! ! j¡.Ó1°CÑ7ˆOÞØð �?‰?œl×/Ñ/Ó/àŸ*™*×;Ñ;¸I¿N¹NÓKˆKØ˜SÓ Øð —^‘^×(Ñ(Ó*¨U¯Z©Z¯_©_Ó->Ñ>ˆ
Ø×$Ñ$ y×';Ñ';Ñ;ˆ	ð Ð!1Ñ2Ó2ØÐ#3Ñ4Ó4ààr!   Úgroup_clustersc                 óf  • SnU Hœ  nSnU H%  nXd:X  a  M
  U R                  XFU5      (       a  M#  Sn  O   U(       d  M9  Uc  UnM@  UR                  R                  5       UR                  R                  5       :”  d  Mx  UR                  UR                  -
  US   ::  d  Mš  UnMž     U(       a  U$ US   $ )zLSelect best cluster from a group of overlapping clusters based on all rules.NTFrc   r   )rÿ   rE   r³   r•   )r   r  rö   Úcurrent_bestrô   Úshould_selectrõ   s          r   Ú_select_best_cluster_from_groupÚ3LayoutPostprocessor._select_best_cluster_from_group  s»   € ð ˆã'ˆIØ ˆMã'�ØÓ%Ùà×2Ñ2°9ÀV×LÓLØ$)�MÙñ (÷ ˆ}ØÑ'Ø#,’Lð "Ÿ™×+Ñ+Ó-°×0AÑ0A×0FÑ0FÓ0HÕHØ(×3Ñ3°i×6JÑ6JÑJØ!Ð"2Ñ3õ4ð (1šñ+ (ö.  ,ˆ|ÐB°ÀÑ1BÐBr!   Úcluster_typerS   rT   c                 óX  • U(       d  / $ US:X  a  U R                   OUS:X  a  U R                  OU R                  nU Vs0 s H  ofR                  U_M     nn[	        UR                  5       5      nU R                  U   n	U H¡  n
UR                  U
R                  5      nX·R                  5       -  nUR                  U
R                  5        U HP  nUR                  U
R                  X|   R                  UU5      (       d  M4  UR                  U
R                  U5        MR     M£     / nUR                  5       R                  5        H×  n[        U5      S:X  a  UR                  X~S      5        M*  U Vs/ s H  o÷U   PM	     nnU R!                  UU	5      nU H0  n
U
U:w  d  M  UR"                  R%                  U
R"                  5        M2     U R'                  UR"                  5      Ul        U R)                  UR"                  5      Ul        UR                  U5        MÙ     U$ s  snf s  snf )Nre   rf   r#   r   )rs   ru   rw   rD   r   ÚkeysÚOVERLAP_PARAMSrO   rE   Údiscardr[   r'   r.   Úvaluesr†   r,   r  rk   r¢   rÝ   rƒ   )r   r;   r  rS   rT   r=   rx   Úvalid_clustersÚufrö   r@   Ú
candidatesÚother_idÚresultÚgroupÚcidr  Úbests                     r   r¥   Ú0LayoutPostprocessor._remove_overlapping_clusters'  sî  € ö ØˆIð ˜yÓ(ð ×Òð ˜yÓ(ð ×#Ò#à×#Ñ#ð 	ñ ,4Ó4ª8 aŸ$™$ š'©8ˆÐ4Ü�~×*Ñ*Ó,Ó-ˆØ×$Ñ$ \Ñ2ˆãˆGØ&×6Ñ6°w·|±|ÓDˆJØ×-Ñ-Ó/Ñ/ˆJØ×Ñ˜wŸz™zÔ*ã&�Ø ×.Ñ.Ø—L‘LØ"Ñ,×1Ñ1Ø%Ø)÷	ó ð —H‘H˜WŸZ™Z¨Ö2ó 'ñ  ð ˆØ—]‘]“_×+Ñ+Ö-ˆEÜ�5‹z˜Q‹Ø—‘˜n°1©XÑ6Ô7Ùá=BÓCºU°c¨SÔ1¹UˆNÐCØ×7Ñ7¸ÈÓOˆDó *�Ø˜d•?Ø—J‘J×%Ñ% g§m¡mÖ4ñ *ð ×0Ñ0°·±Ó<ˆDŒJØ×)Ñ)¨$¯*©*Ó5ˆDŒJØ�M‰M˜$Öñ .ð" ˆùòI 5ùò0 Ds   ¾H"Å3H'rb   rc   c                 óÞ  • SnU HØ  nSnU Hh  nXu:X  a  M
  UR                   R                  5       UR                   R                  5       -  nUR                  UR                  -
  n	X‚::  d  M_  X“:”  d  Mf  Sn  O   U(       d  M|  UbW  UR                   R                  5       UR                   R                  5       :”  d  M·  UR                  UR                  -
  U::  d  MÖ  UnMÚ     U(       a  U$ US   $ )zHIteratively select best cluster based on area and confidence thresholds.NTFr   )rE   r³   r•   )
r   r;   rb   rc   r  rô   r  rõ   rû   rþ   s
             r   Ú_select_best_clusterÚ(LayoutPostprocessor._select_best_cluster`  sØ   € ð ˆÛ!ˆIØ ˆMÛ!�ØÓ%Ùà&Ÿ^™^×0Ñ0Ó2°U·Z±Z·_±_Ó5FÑF�
Ø!×,Ñ,¨y×/CÑ/CÑC�	àÕ/°IÕ4NØ$)�MÙñ "÷ ˆ}ØÑ'Ø—N‘N×'Ñ'Ó)¨L×,=Ñ,=×,BÑ,BÓ,DÕDØ$×/Ñ/°)×2FÑ2FÑFÈ.ÕXà#,’Lñ% "ö(  ,ˆ|Ð<°¸!±Ð<r!   rk   c                 ó¬   • [        5       n/ nU HA  nUR                  U;  d  M  UR                  UR                  5        UR                  U5        MC     U$ )zJEnsure each cell appears only once, maintaining order of first appearance.)rM   Úindexrä   r,   )r   rk   Úseen_idsÚunique_cellsrª   s        r   rÝ   Ú&LayoutPostprocessor._deduplicate_cells~  sJ   € ä“5ˆØˆÛˆDØ�z‰z Õ)Ø—‘˜TŸZ™ZÔ(Ø×#Ñ# DÖ)ñ ð Ðr!   Úmin_overlapc                 ó  • U H
  n/ Ul         M     U Vs0 s H  o3R                  U_M     nn[        U5      n[        U5       VVs0 s H  u  pcUR                  U_M     nnn[	        U5      nU R                    HÙ  n	U	R
                  R                  5       (       d  M$  U	R                  R                  5       n
U
R                  5       S::  a  MT  UnSnUR                  U
5      U-  n[        X×R                  S9 H6  nXN   nU
R                  [        UR                  5      5      nXû:”  d  M2  UnUnM8     Uc  M¾  UR                   R!                  U	5        MÛ     U H#  nU R#                  UR                   5      Ul         M%     U$ s  snf s  snnf )z)Assign cells to best overlapping cluster.r   Nr¹   )rk   rD   rM   rŸ   r9   ÚtextÚstripÚrectr¡   r³   rO   ÚsortedÚ__getitem__rW   r   rE   r,   rÝ   )r   r;   r  r@   Úcluster_by_idÚcluster_idsÚorderÚcluster_orderÚcluster_indexrª   Ú	cell_bboxÚbest_overlapÚbest_clusterÚcandidate_idsÚ
cluster_idÚoverlap_ratios                   r   r™   Ú-LayoutPostprocessor._assign_cells_to_clustersˆ  sm  € ó  ˆGØˆGŽMñ  ñ =EÓEºH°Ÿ™ WÒ,¹HˆÐEÜ˜-Ó(ˆÜAJÈ8ÔATÔUÒAT©~¨u˜Ÿ™ UÒ*ÑATˆÑUÜ+¨HÓ5ˆà—J”JˆDØ—9‘9—?‘?×$Ñ$ÙàŸ	™	×1Ñ1Ó3ˆIØ�~‰~Ó 1Ó$Ùà&ˆLØˆLØ)×9Ñ9¸)ÓDÀ{ÑRˆMä$ ]×8QÑ8QÔR�
Ø'Ñ3�à )× @Ñ @Ü(¨¯©Ó6ó!�ð !Õ/Ø#0�LØ#*’Lñ Sð Ó'Ø×"Ñ"×)Ñ)¨$Ö/ñ/ ó4  ˆGØ ×3Ñ3°G·M±MÓBˆGŽMñ  ð ˆùòE FùãUs   •FÁFc                 ó  • U VVs1 s H!  o"R                     H  o3R                  iM     M#     nnnU R                    Vs/ s H8  nUR                  U;  d  M  UR                  R                  5       (       d  M6  UPM:     sn$ s  snnf s  snf )z'Find cells not assigned to any cluster.)rk   r  r   r!  )r   r;   r@   rª   Úassigneds        r   rœ   Ú*LayoutPostprocessor._find_unassigned_cells³  sr   € á.6ÔQªh 7Ç=Å=¸4—J”JÁ=‘J©hˆÑQð Ÿ
š
ó
â"�Ø�z‰z Ñ)ó à.2¯i©i¯o©o×.?÷ Ù"ñ
ð 	
ùó Rùò
s   †(B¿BÁBÁ8Bc           
      óÚ  • U GHc  nUR                   (       d  M  [        [        S UR                    5       5      [        S UR                    5       5      [        S UR                    5       5      [        S UR                    5       5      S9nUR                  [
        R                  :X  a´  [        [        UR                  R                  UR                  5      [        UR                  R                  UR                  5      [        UR                  R                  UR                  5      [        UR                  R                  UR                  5      S9Ul        GM]  X2l        GMf     U$ )z5Adjust cluster bounding boxes to contain their cells.c              3   óh   #   • U  H(  oR                   R                  5       R                  v •  M*     g 7fr   )r"  r¡   rÑ   ©r�   rª   s     r   r‘   Ú=LayoutPostprocessor._adjust_cluster_bboxes.<locals>.<genexpr>Ã  ó!   é € ÐNÂ¸—i‘i×/Ñ/Ó1×3Ö3Âùó   ‚02c              3   óh   #   • U  H(  oR                   R                  5       R                  v •  M*     g 7fr   )r"  r¡   r×   r6  s     r   r‘   r7  Ä  r8  r9  c              3   óh   #   • U  H(  oR                   R                  5       R                  v •  M*     g 7fr   )r"  r¡   rÙ   r6  s     r   r‘   r7  Å  r8  r9  c              3   óh   #   • U  H(  oR                   R                  5       R                  v •  M*     g 7fr   )r"  r¡   rÛ   r6  s     r   r‘   r7  Æ  r8  r9  rÜ   )rk   r   rÁ   rž   ro   r   rë   rE   rÑ   r×   rÙ   rÛ   )r   r;   r@   Ú
cells_bboxs       r   r¤   Ú*LayoutPostprocessor._adjust_cluster_bboxes¼  sî   € äˆGØ—=—=Ùä$ÜÑNÀÇÂÓNÓNÜÑNÀÇÂÓNÓNÜÑNÀÇÂÓNÓNÜÑNÀÇÂÓNÓNñ	ˆJð �}‰}¤× 2Ñ 2Ó2ä*Ü˜'Ÿ,™,Ÿ.™.¨*¯,©,Ó7Ü˜'Ÿ,™,Ÿ.™.¨*¯,©,Ó7Ü˜'Ÿ,™,Ÿ.™.¨*¯,©,Ó7Ü˜'Ÿ,™,Ÿ.™.¨*¯,©,Ó7ñ	 �—ð  *—ñ)  ð, ˆr!   c                 ó   • [        US S9$ )z(Sort cells by their source/parser index.c                 ó   • U R                   $ r   ©r  )rx   s    r   r¶   Ú1LayoutPostprocessor._sort_cells.<locals>.<lambda>Ø  s   € ¨1¯7ª7r!   r¹   ©r#  )r   rk   s     r   rƒ   ÚLayoutPostprocessor._sort_cellsÖ  s   € ä�eÑ!2Ñ3Ð3r!   r|   c                 ól   • US:X  a  [        US S9$ US:X  a  [        US S9$ US:X  a  [        US S9$ U$ )z5Sort clusters for deterministic layout-stage storage.rD   c                 óÒ   • U R                   (       a  [        S U R                    5       5      O[        R                  U R                  R
                  U R                  R                  4$ )Nc              3   ó8   #   • U  H  oR                   v •  M     g 7fr   rA  r6  s     r   r‘   ÚGLayoutPostprocessor._sort_clusters.<locals>.<lambda>.<locals>.<genexpr>ã  s   é € ÐA²=¨4ŸJžJ²=ùr“   )rk   rÁ   ÚsysÚmaxsizerE   r×   rÑ   ©r@   s    r   r¶   Ú4LayoutPostprocessor._sort_clusters.<locals>.<lambda>á  sA   € ð #Ÿ=Ÿ=ô ÑA°7·=²=ÓAÔAä Ÿ[™[à—L‘L—N‘NØ—L‘L—N‘Nñ%r!   r¹   Útblrc                 óZ   • U R                   R                  U R                   R                  4$ r   )rE   r×   rÑ   rK  s    r   r¶   rL  í  ó   € ¨w¯|©|¯~©~¸w¿|¹|¿~¹~Ñ.Nr!   Úlrtbc                 óZ   • U R                   R                  U R                   R                  4$ r   )rE   rÑ   r×   rK  s    r   r¶   rL  ñ  rO  r!   rC  )r   r;   r|   s      r   r�   Ú"LayoutPostprocessor._sort_clustersÚ  s_   € ð �4‹<ÜØññð ð �V‹^ÜØÑNñð ð �V‹^ÜØÑNñð ð ˆOr!   )
rn   rk   ri   rh   rm   ru   rq   rs   rr   rw   )r°   gš™™™™™¹?)r°   r°   )rd   r�   )=r0   r1   r2   r3   r4   r
  r   ÚFORMÚKEY_VALUE_REGIONr¾   rë   rì   r   r'   rv   rt   rp   ÚCAPTIONÚFOOTNOTEr›   rø   ÚPAGE_FOOTERÚPAGE_HEADERÚSECTION_HEADERr    ÚTITLErú   ÚCHECKBOX_SELECTEDÚCHECKBOX_UNSELECTEDr—   r˜   r	   r+   r   r
   r   r‹   r}   r~   rÀ   Ústaticmethodr]   rM   r5   rè   r¿   r   r^   rÿ   r  Ústrr¥   r  r   rÝ   r™   rœ   r¤   rƒ   r�   r6   r7   r!   r   r`   r`   l   sQ  † ÙUð '*¸TÑBØ&)¸SÑAØ&)¸SÑAñ€Nð 	×ÑØ×%Ñ%ð€Oð
 	×ÑØ×#Ñ#ð€Kð $×)Ñ)¨+Ó6€MØ!×'Ñ'¨×)=Ñ)=Ð(>Ó?€MðØ×Ñ˜cðà×Ñ˜sðð 	×Ñ˜cðð 	×Ñ ð	ð
 	× Ñ  #ðð 	× Ñ  #ðð 	×Ñ˜cðð 	×#Ñ# Tðð 	×Ñ˜Cðð 	×Ñ˜3ðð 	×Ñ˜Dðð 	×Ñ˜4ðð 	×&Ñ&¨ðð 	×(Ñ(¨$ðð 	×Ñ˜4ðð  	×%Ñ% tð!ð" 	×#Ñ# Tð#Ðð, 	×Ñ˜L×7Ñ7ð€Oð

àð
ð �w‘-ð
ð 0ð	
ð
 
ô
ð6%˜T '™]ô %ðN8¨4°©=ô 8ðtvF¨4°©=ô vFðp¨Wð ÀÀWÁð ÐRVô ð, ð  #Ø #ñ	Ø�W‘ðà�g‘ðð ðð ð	ð
 
ˆS‰ôó ðð4!O¸tÀG¹}ô !OðF"Ø ð"Ø)0ð"Ø:>ð"à	ô"ðHCà˜W™ðCð ðCð 
ô	CðJ $'Ø'*ñ7à�w‘-ð7ð ð7ð !ð	7ð
  %ð7ð 
ˆg‰õ7ðr=à�w‘-ð=ð ð=ð ð	=ð
 
ô=ð<¨¨X©ð ¸4À¹>ô ð =@ñ)Ø˜W™ð)Ø49ð)à	ˆg‰õ)ðV
¨t°G©}ð 
ÀÀhÁô 
ð¨t°G©}ð ÀÀgÁô ð44  h¡ð 4°D¸±Nô 4ð
 48ñØ˜W™ðØ-0ðà	ˆg‰÷ð r!   r`   )ÚloggingrI  Úcollectionsr   Údocling_core.types.docr   r   r   Údocling_core.types.doc.pager   Údocling.datamodel.base_modelsr   r	   Ú"docling.datamodel.pipeline_optionsr
   Údocling.datamodel.spatialr   r   r   Ú	getLoggerr0   Ú_logr   r9   r`   r7   r!   r   Ú<module>rh     s]   ðó Û 
Ý #ç BÑ BÝ 0ç 7Ý M÷ñ ð ×Ò˜Ó"€÷ñ ÷B2
ñ 2
÷jH
ò H
r!   