
    khk*                     F    d Z ddlZddlZddlmZ ddlmZ  G d de      Zy)a  Object with a bounding box, e.g. Block, Line, Span.

Based on ``PyMuPDF``, the coordinates (e.g. bbox of ``page.get_text('rawdict')``) are generally
provided relative to the un-rotated page; while this ``pdf2docx`` library works under real page
coordinate system, i.e. with rotation considered. So, any instances created by this Class are
always applied a rotation matrix automatically.

Therefore, the bbox parameter used to create ``Element`` instance MUST be relative to un-rotated
CS. If final coordinates are provided, should update it after creating an empty object::

    Element().update_bbox(final_bbox)

.. note::
    An exception is ``page.get_drawings()``, the coordinates are converted to real page CS already.
    N   )IText)	constantsc            	       *   e Zd ZdZ ej
                  d      Zed        Zed        Z	d de
fdZd Zd	 Zed
        Zej                   d        Zd ZdefdZd Zd Zd!dd defdZd"defdZd#dedefdZd#dedefdZd Zd Zd$dedededefdZy)%Elementz.Boundary box with attribute in fitz.Rect type.        c                 N    |r#t        |t        j                        r|| _        yyy)zlSet global rotation matrix.

        Args:
            Rotation_matrix (fitz.Matrix): target matrix
        N)
isinstancefitzMatrixROTATION_MATRIX)clsrotation_matrixs     S/var/www/teggl/fontify/venv/lib/python3.12/site-packages/pdf2docx/common/Element.pyset_rotation_matrixzElement.set_rotation_matrix   s$     z/4;;G"1C  H?    c                 \    | j                   \  }}}}}}t        j                  ||||dd      S )zHPure rotation matrix used for calculating text direction after rotation.r   )r   r   r   )r   abcdefs          r   pure_rotation_matrixzElement.pure_rotation_matrix*   s4     ))!Aa!{{1Qq1Q''r   Nrawc                     t        j                         | _        || _        d|xs i v r;t        j                  |d         t        j
                  z  }| j                  |       yy)zJ Initialize Element and convert to the real (rotation considered) page CS.bboxN)r   Rectr   _parentr   r   update_bbox)selfr   parentrects       r   __init__zElement.__init__1   sT    IIK	 ciR 99S[)G,C,CCDT" !r   c                 ,    t        | j                        S )z!Real object when bbox is defined.)boolr   r!   s    r   __bool__zElement.__bool__=   s     DIIr   c                 `    | j                   j                   dt        | j                         dS )N())	__class____name__tupler   r'   s    r   __repr__zElement.__repr__I   s)    $.."9"9!:!E$))<L;MQOOr   c                     | j                   S Nr   r'   s    r   r"   zElement.parentO   s    !\\)r   c                     || _         y r1   r2   )r!   r"   s     r   r"   zElement.parentR   s	    -3dlr   c                 f    | j                   dc}| _        t        j                  |       }|| _         |S )zmake a deep copy.N)r   r"   copydeepcopy)r!   r"   objs      r   r5   zElement.copyY   s0     #llDmmD!
r   dtc                 ,    | j                   | | ||fz   S )a  Get expanded bbox with margin in both x- and y- direction.

        Args:
            dt (float): Expanding margin.

        Returns:
            fitz.Rect: Expanded bbox.

        .. note::
            This method creates a new bbox, rather than changing the bbox of itself.
        )r   )r!   r8   s     r   get_expand_bboxzElement.get_expand_bboxc   s      yyRC"b"---r   c           	      t    t        j                  |D cg c]  }t        |d       c}      | _        | S c c}w )zUpdate current bbox to specified ``rect``.

        Args:
            rect (fitz.Rect or list): bbox-like ``(x0, y0, x1, y1)``,
                in real page CS (with rotation considered).
        r   )r   r   roundr   )r!   r#   xs      r   r    zElement.update_bboxr   s/     II48auQqz89	 9s   5c                 R    | j                  | j                  |j                  z        S )zUpdate current bbox to the union with specified Element.

        Args:
            e (Element): The target to get union

        Returns:
            Element: self
        )r    r   )r!   r   s     r   
union_bboxzElement.union_bbox}   s"     		AFF 233r   r   	thresholdc                    |j                   j                         }|sy| j                   |j                   z  }t        |j                         |z  d      }||k  ry| j                   j                  | j                   j                  k\  r>| j                   j                  t
        j                  z   |j                   j                  k\  S | j                   j                  t
        j                  z   |j                   j                  k\  S )a5  Whether given element is contained in this instance, with margin considered.

        Args:
            e (Element): Target element
            threshold (float, optional): Intersection rate.
                Defaults to 1.0. The larger, the stricter.

        Returns:
            bool: [description]
        F   )r   get_arear<   widthheightr   
MINOR_DIST)r!   r   r@   Sintersectionfactors         r   containszElement.contains   s     FFOO yy166)|,,.q0!4)E 99??dii...99??9#7#77166<<GGyy	 4 44EEr   c                 6   | j                   }t        |d      r|j                   nt        j                  |      }||z  }|j                  ry|j                         |j                         |j                         }}}|r|t        ||      z  nd}	|	|k\  r||z  S dS )aC  If the intersection with ``e`` exceeds the threshold, return the union of
        these two elements; else return None.

        Args:
            e (Element): Target element.
            threshold (float, optional): Intersection rate. Defaults to 0.95.

        Returns:
            fitz.Rect: Union bbox or None.
        r   Ngư>)r   hasattrr   r   is_emptyrC   min)
r!   r   r@   bbox_1bbox_2r   a1a2r   rI   s
             r   get_main_bboxzElement.get_main_bbox   s     "1f-499Q< VO::d OO%v'8!**,B!"3r":"(I"5v?4?r   rI   text_directionc                    |rt        |       sy|r| j                  rdnd}| j                  |dz      | j                  |   z
  }|j                  |dz      |j                  |   z
  }t        | j                  |dz      |j                  |dz            t	        | j                  |   |j                  |         z
  }d}||z   |z
  |z   |t	        ||      z  k\  S )a  Check whether two Element instances have enough intersection in vertical direction,
        i.e. perpendicular to reading direction.

        Args:
            e (Element): Object to check with
            factor (float, optional): Threshold of overlap ratio, the larger it is, the higher
                probability the two bbox-es are aligned.
            text_direction (bool, optional): Consider text direction or not. True by default.

        Returns:
            bool: [description]

        Examples::

            +--------------+
            |              |
            +--------------+
                    L1
                    +-------------------+
                    |                   |
                    +-------------------+
                            L2

        An enough intersection is defined based on the minimum width of two boxes::

            L1+L2-L>factor*min(L1,L2)
        Fr   r   rB   MbP?r&   is_vertical_textr   maxrN   	r!   r   rI   rT   idxL1L2Lepss	            r   vertically_align_withzElement.vertically_align_with   s    8 T
5 "d&;&;aYYs1udiin,VVCE]166#;&		#a% !&&Q-03tyy~qvvc{3SS"uQws{fSBZ///r   c                    |rt        |       sy|r| j                  rdnd}| j                  |dz      | j                  |   z
  }|j                  |dz      |j                  |   z
  }t        | j                  |dz      |j                  |dz            t	        | j                  |   |j                  |         z
  }d}||z   |z
  |z   |t	        ||      z  k\  S )a  Check whether two Element instances have enough intersection in horizontal direction,
        i.e. along the reading direction.

        Args:
            e (Element): Element to check with
            factor (float, optional): threshold of overlap ratio, the larger it is, the higher
                probability the two bbox-es are aligned.
            text_direction (bool, optional): consider text direction or not. True by default.

        Examples::

            +--------------+
            |              | L1  +--------------------+
            +--------------+     |                    | L2
                                 +--------------------+

        An enough intersection is defined based on the minimum width of two boxes::

            L1+L2-L>factor*min(L1,L2)
        Fr   r   rB   rV   rW   rZ   s	            r   horizontally_align_withzElement.horizontally_align_with   s    * T
5 "d&;&;aYYs1udiin,VVCE]166#;&		#a% !&&Q-03tyy~qvvc{3SS"uQws{fSBZ///r   c                 J   |r| j                   |j                   k7  ry| j                   rdnd}| j                  |   | j                  |dz      z   dz  }|j                  |   |j                  |dz      z   dz  }||j                  |dz      k  xr || j                  |dz      k  }|S )a  Check whether in same row/line with specified Element instance.
        With text direction considered.

           Taking horizontal text as an example:

           * yes: the bottom edge of each box is lower than the centerline of the other one;
           * otherwise, not in same row.

        Args:
            e (Element): Target object.

        .. note::
            The difference to method ``horizontally_align_with``: they may not in same line, though
            aligned horizontally.
        Fr   r   rB   g       @)is_horizontal_textr   )r!   r   r[   c1c2ress         r   in_same_rowzElement.in_same_row  s      D++q/C/CC **aiintyyQ//36ffSkAFF3q5M)S0!&&Q-8B		#a%(8$8
r   c                 >    dt        d | j                  D              iS )zStore properties in raw dict.r   c              3       K   | ]  }|  y wr1    ).0r=   s     r   	<genexpr>z Element.store.<locals>.<genexpr>-  s     4Qq4s   )r.   r   r'   s    r   storezElement.store+  s    4$))4466r   strokerD   filldashesc           	      H    |j                  | j                  ||||dd       y)z(Plot bbox in PDF page for debug purpose.F      ?)colorrp   rD   rq   overlayfill_opacityN)	draw_rectr   )r!   pagero   rD   rp   rq   s         r   plotzElement.plot0  s+    tyy# "$$$' 	 	)r   )NN)g      ?)gffffff?)r   T))r   r   r   rs   NN) r-   
__module____qualname____doc__r   r   r   classmethodr   r   dictr$   r(   r/   propertyr"   setterr5   floatr:   r    r?   rJ   rS   r&   r`   rb   rh   rn   r.   strry   rk   r   r   r   r      s   8 "dkk#&O 2 2 ( (	#4 	#	 P ) )]]3 3. .	4F Fe F8@ @2&0e &0 &0R0 0$ 0D>7
) )U )U )X[ )r   r   )r|   r5   r   sharer    r   r   rk   r   r   <module>r      s&        a)e a)r   