
    'jE                    @   d dl mZ d dlmZmZ d dlZd dlmZ d dlm	Z	 d dl
mZ d dlmZmZmZmZmZ d dlmZmZmZmZmZmZ d d	lmZ g d
ZdZdZdZdZdZ ej!         G d d                      Z" G d d          Z#d1dZ$d2dZ%d3d Z&d4d"Z'd5d%Z(d6d'Z)d7d-Z*d8d0Z+dS )9    )annotations)IterableSequenceN)const)Tags)dxftag)SpatialFilter	DXFEntity
DictionaryInsertXRecord)Vec2Vec3UVecZ_AXISMatrix44BoundingBox2d)RoundtripXRecord)get_spatial_filterXClipClippingPathACAD_FILTERACAD_XREC_ROUNDTRIPACAD_INVERTEDCLIP_ROUNDTRIP#ACAD_INVERTEDCLIP_ROUNDTRIP_COMPARESPATIALc                      e Zd ZU dZ e            Zded<    e            Zded<    e            Zded<   dZ	ded<   dd
Z
ddZdS )r   a  Stores the SPATIAL_FILTER clipping paths in original form that I still don't fully
    understand for `inverted` clipping paths. All boundary paths are simple polygons as a
    sequence of :class:`~ezdxf.math.Vec2`.

    Attributes:
        vertices: Contains the boundary polygon for regular clipping paths.
            Contains the outer boundary path for inverted clippings paths - but not always!
        inverted_clip:
            Contains the inner boundary for inverted clipping paths - but not always!
        inverted_clip_compare:
            Contains the combined inner- and the outer boundaries for inverted
            clipping paths - but not always!
        is_inverted_clip: ``True`` for inverted clipping paths

    Sequence[Vec2]verticesinverted_clipinverted_clip_compareFboolis_inverted_clipreturnc                    | j         s| j        S | j        }t          | j                  t          |          k     r| j        }|S )z7Returns the inner clipping polygon as sequence of Vec2.)r#   r   	bbox_arear    )selfinner_polygons     E/DATA/AppData/hermes/venv/lib/python3.11/site-packages/ezdxf/xclip.pyr(   zClippingPath.inner_polygon/   sJ     $ 	!= T'((9]+C+CCC .M    r   c                `    | j         st          | j                  S t          | j                  S )z-Returns the maximum extents as BoundingBox2d.)r#   r   r   r!   r'   s    r)   outer_boundszClippingPath.outer_bounds:   s0    $ 	0 /// T7888r*   Nr$   r   )r$   r   )__name__
__module____qualname____doc__tupler   __annotations__r    r!   r#   r(   r-    r*   r)   r   r      s             %uwwH&&&&$)EGGM++++,1EGG3333"""""	 	 	 	9 9 9 9 9 9r*   r   c                      e Zd ZdZd'dZd(dZd)d
Zed*d            Zed*d            Z	ed*d            Z
d+dZd+dZd,dZd,dZd-dZd-dZ	 d.ddd/dZd0dZd1d#Zd+d$Zd+d%Zd& ZdS )2r   a}  Helper class to manage the clipping path of INSERT entities.

    Provides a similar functionality as the XCLIP command in CAD applications.

    .. important::

        This class handles only 2D clipping paths.

    The visibility of the clipping path can be set individually for each block
    reference, but the HEADER variable $XCLIPFRAME ultimately determines whether the
    clipping path is displayed or plotted by the application:

    === =============== ===
    0   not displayed   not plotted
    1   displayed       not plotted
    2   displayed       plotted
    === =============== ===

    The default setting is 2.

    insertr   r$   Nonec                    t          |t                    s$t          j        dt	          |                     || _        t          |          | _        d S )NzINSERT entity required, got )
isinstancer   r   DXFTypeErrorstr_insertr   _spatial_filter)r'   r7   s     r)   __init__zXClip.__init__Z   sR    &&)) 	S$%QCKK%Q%QRRR1&99r*   SpatialFilter | Nonec                    | j         S )zReturns the underlaying SPATIAL_FILTER entity if the INSERT entity has a
        clipping path and returns ``None`` otherwise.
        r>   r,   s    r)   r   zXClip.get_spatial_filter`   s     ##r*   intc                l    d}| j         j        %| j         j        j                            dd          }|S )N   z$XCLIPFRAME)r=   docheaderget)r'   policys     r)   get_xclip_frame_policyzXClip.get_xclip_frame_policyf   s4    <'\%,00BBFr*   r"   c                    | j         duS )z1Returns if the INSERT entity has a clipping path.NrB   r,   s    r)   has_clipping_pathzXClip.has_clipping_pathl   s     #4//r*   c                v    t          | j        t                    rt          | j        j        j                  S dS )z8Returns ``True`` if block reference clipping is enabled.F)r:   r>   r	   r"   dxfis_clipping_enabledr,   s    r)   rO   zXClip.is_clipping_enabledq   s6     d*M:: 	F,0DEEEur*   c                f    t          | j                  }|dS |                    t                    S )z.Returns ``True`` if clipping path is inverted.NF)get_roundtrip_xrecordr>   has_sectionr   )r'   xrecs     r)   r#   zXClip.is_inverted_clipx   s3     %T%9::<5 ;<<<r*   c                `    t          | j        t                    rd| j        j        _        dS dS )z Enable block reference clipping.   Nr:   r>   r	   rN   rO   r,   s    r)   enable_clippingzXClip.enable_clipping   5    d*M:: 	=;<D $888	= 	=r*   c                `    t          | j        t                    rd| j        j        _        dS dS )z!Disable block reference clipping.r   NrV   r,   s    r)   disable_clippingzXClip.disable_clipping   rX   r*   r   c                   g }t          | j        t                    st                      S | j        j        }t          j        |                    | j        j                            }t          |          dk    rt          |          }t          |d          }t          | j                  }t          |t                    r=t          |t          |          |_        t          |t           |          |_        d|_        |S )zNReturns the clipping path in block coordinates (relative to the block origin).rE   Fr#   T)r:   r>   r	   r   inverse_insert_matrixr   r3   transform_verticesboundary_verticeslen
_rect_pathrQ   r   get_roundtrip_verticesr   r    r   r!   r#   )r'   r   mclipping_pathrS   s        r)   get_block_clipping_pathzXClip.get_block_clipping_path   s    #%$.>> 	">>! 6:  !5!GHH
 
 x==A!(++H$XFFF$T%9::d,-- 	2*@11+ +M' 3I913 3M/ .2M*r*   c                   t                      }t          | j        t                    st	          ||          S |                                 }| j                                        }t          j         |	                    |j
                            }t          |          dk    r!t          |                                          }t	          ||j                  }|j        rt          j         |	                    |j                            }t          |          dk    r!t          |                                          }||_        t          j         |	                    |j                            |_        |S )zReturns the clipping path in WCS coordinates (relative to the WCS origin) as
        2D path projected onto the xy-plane.
        rE   r\   )r3   r:   r>   r	   r   re   r=   matrix44r   r^   r   r`   r   rect_verticesr#   r    r!   )r'   r   block_clipping_pathrc   wcs_clipping_pathr    s         r)   get_wcs_clipping_pathzXClip.get_wcs_clipping_path   s\    $)77$.>> 	4(333"::<<L!!##:a223F3OPPQQx==A$X..<<>>H(':'K
 
 
 / 		 J$$%8%FGG M =!!Q&& -m < < J J L L.;+6:j$$%8%NOO7 73 ! r*   r   Iterable[UVec]c                   | j         t          | j                  | _         | j         }|                    |           t	          ddd          |j        _        t          |j        _        d|j        _	        d|j        _
        d|j        _        d|j        _        t                      }|                    |           |                    |           |                                  dS )a  Set clipping path in block coordinates (relative to block origin).

        The clipping path is located in the xy-plane, the z-axis of all vertices will
        be ignored.  The clipping path doesn't have to be closed (first vertex != last vertex).
        Two vertices define a rectangle where the sides are parallel to x- and y-axis.

        Raises:
           DXFValueError: clipping path has less than two vertrices

        Nr           )r>   new_spatial_filterr=   set_boundary_verticesr   rN   originr   	extrusionhas_front_clipping_planefront_clipping_plane_distancehas_back_clipping_planeback_clipping_plane_distancer   set_inverse_insert_matrixset_transform_matrix_discard_inverted_clip)r'   r   spatial_filterrc   s       r)   set_block_clipping_pathzXClip.set_block_clipping_path   s     '#5dl#C#CD -,,X666$(AqMM!'-$673;>8562:=7
 JJ00333++A...##%%%%%r*   c                Z   | j                                         }	 |                                 n# t          $ r t          d          w xY wt	          j        |          }t          |          dk    rt          |          }|                     |	                    |                     dS )a   Set clipping path in WCS coordinates (relative to WCS origin).

        The clipping path is located in the xy-plane, the z-axis of all vertices will
        be ignored. The clipping path doesn't have to be closed (first vertex != last vertex).
        Two vertices define a rectangle where the sides are parallel to x- and y-axis.

        Raises:
           DXFValueError: clipping path has less than two vertrices
           ZeroDivisionError: Block reference transformation matrix is not invertible

        z8Block reference transformation matrix is not invertible.rE   N)
r=   rg   inverseZeroDivisionErrorr   listr`   ra   r{   r^   )r'   r   rc   	_verticess       r)   set_wcs_clipping_pathzXClip.set_wcs_clipping_path   s     L!!##	IIKKKK  	 	 	#J  	 Ih''	y>>Q"9--I$$Q%9%9)%D%DEEEEEs	   0 A
NF)ignore_acad_compatibilityextentsIterable[UVec] | Nonec                  |du rdS |                                  }t          |j                  dk     rt          j        d          |j        rt          j        d          | j        j        J | j        j                            d           d}|| 	                                }d}t          |          }|                    |j                   |j        st          j        d	          |r*|                    t          |j                  |z             |j        }t!          ||          }|                     |           |                     ||           dS )
a,  Invert clipping path. (experimental feature)

        The outer boundary is defined by the bounding box of the given `extents`
        vertices or auto-detected if `extents` is ``None``.

        The `extents` are BLOCK coordinates.
        Requires an existing clipping path and that clipping path cannot be inverted.

        .. warning::

            You have to set the flag `ignore_acad_compatibility` to ``True`` to use
            this feature.  AutoCAD will not load DXF files with inverted clipping paths
            created by ezdxf!!!!

        FNrE   zno clipping path setz!clipping path is already invertedzN
AutoCAD will not load DXF files with inverted clipping paths created by ezdxfrn   g?zextents not detectable)re   r`   r   r   DXFValueErrorr#   r=   rF    add_acad_incompatibility_message_detect_block_extentsr   extendhas_datagrowmaxsize#_get_inverted_clip_compare_verticesr{   _set_inverted_clipping_path)r'   r   r   current_clipping_pathgrow_factorbboxr    r!   s           r)   invert_clipping_pathzXClip.invert_clipping_path   su   $ %--F $ < < > >$-..22%&<=== 1 	K%&IJJJ|+++99]	
 	
 	
 ?0022G KW%%)2333} 	@%&>??? 	4IIc$)nn{2333 .6 CD- X X$$%:;;;((8MNNNNNr*   r   c                .   ddl m} | j        }|j        }|
J d            t	                      }|j                            |j        j                  }||S |	                    |d          }|j
        s|S t          j        |j        |j        g          S )Nr   )r   zvalid DXF document requiredT)fast)ezdxfr   r=   rF   r3   blocksrH   rN   namer   r   r   extminextmax)r'   r   r7   rF   no_verticesblock_bboxs          r)   r   zXClip._detect_block_extents)  s    j =&+gg
vz//=U..~ 	z5<6777r*   clip_verticesIterable[Vec2]compare_verticesc                R   | j         }t          |t                    sJ t          |          }|t	          |          }t          d |D                       }t          d |D                       }|                    t          |           |                    t          |           d S )Nc              3  P   K   | ]!}t          d t          |                    V  "dS 
   Nr   r   .0vs     r)   	<genexpr>z4XClip._set_inverted_clipping_path.<locals>.<genexpr>B  s2      DDDGG,,DDDDDDr*   c              3  P   K   | ]!}t          d t          |                    V  "dS r   r   r   s     r)   r   z4XClip._set_inverted_clipping_path.<locals>.<genexpr>C  s2      JJAF2tAww//JJJJJJr*   )	r>   r:   r	   rQ   new_roundtrip_xrecordr   set_sectionr   r   )r'   r   r   rz   rS   	clip_tagscompare_tagss          r)   r   z!XClip._set_inverted_clipping_path9  s     -.-88888$^44<(88DDDmDDDDD	JJ9IJJJJJ4i@@@<lKKKKKr*   c                   t          | j        t                    sdS | j                                        }|                    t                     | j        j        j        }|J |	                    | j                   d| _        dS )zDelete the clipping path. The clipping path doesn't have to exist.

        This method does not discard the extension dictionary of the base entity,
        even when its empty.
        N)
r:   r>   r	   r=   get_extension_dictdiscardr   rF   entitydbdelete_entity)r'   xdictr   s      r)   discard_clipping_pathzXClip.discard_clipping_pathG  s     $.>> 	F//11k"""<#,###t3444#r*   c                p    t          | j        t                    r| j                                         d S d S N)r:   r>   r	   discard_extension_dictr,   s    r)   ry   zXClip._discard_inverted_clipW  s<    d*M:: 	: 7799999	: 	:r*   c                8    | j                                          dS )z?Discard the extension dictionary of the base entity when empty.N)r=   discard_empty_extension_dictr,   s    r)   cleanupzXClip.cleanup[  s    1133333r*   )r7   r   r$   r8   )r$   r@   )r$   rC   )r$   r"   )r$   r8   )r$   r   )r   rl   r$   r8   r   )r   r   r$   r8   r.   )r   r   r   r   r$   r8   )r/   r0   r1   r2   r?   r   rJ   propertyrL   rO   r#   rW   rZ   re   rk   r{   r   r   r   r   r   ry   r   r5   r*   r)   r   r   C   s        ,: : : :$ $ $ $    0 0 0 X0    X = = = X== = = =
= = = =
   0! ! ! !6& & & &<F F F F2 044ORW4O 4O 4O 4O 4O 4Ol8 8 8 8 L L L L$ $ $ $ : : : :4 4 4 4 4r*   r   r   r   r$   r   c                D    t          |                                           S )zcReturns the path vertices for the smallest rectangular boundary around the given
    vertices.
    )r   rh   )r   s    r)   ra   ra   `  s     ""00222r*   r   r   holec                b    ddl m} | j        | j        J  |t	          |          |           S )Nr   )make_inverted_clipping_polygon)r(   r-   )ezdxf.math.clippingr   r   r   r   )r   r   r   s      r)   r   r   g  sI    
 CBBBBBK#$+*A*AB))T

QUVVVVr*   entityr
   r@   c                   	 |                                  }n# t          $ r Y dS w xY w|                    t                    }t	          |t
                    sdS |                    t                    }t	          |t                    r|S dS )zReturns the underlaying SPATIAL_FILTER entity if the given `entity` has a
    clipping path and returns ``None`` otherwise.
    N)r   AttributeErrorrH   r   r:   r   r   r	   )r   r   acad_filteracad_spatial_filters       r)   r   r   r  s    ))++   tt))K((Kk:.. t%//'22%}55 #""4s    
%%r	   c                   | j         }|t          j        d          	 |                                 }n$# t          $ r |                                 }Y nw xY w|j                            t          d          }|	                    t                    }t          |t                    sB|j                            dd|j        j        i          }|                    t          |           t          |t                    sJ |S )zoCreates the extension dict, the sub-dictionary ACAD_FILTER and the SPATIAL_FILTER
    entity if not exist.
    Nz/Cannot add new clipping path to virtual entity.T)
hard_ownedSPATIAL_FILTERowner)rF   r   r;   r   r   new_extension_dict
dictionaryget_required_dictr   rH   r   r:   r	   objectsadd_dxf_object_with_reactorrN   handleadd)r   rF   r   acad_filter_dictrz   s        r)   ro   ro     s    *C
{ !RSSS,))++ , , ,))++,'99+RV9WW%))'22Nnm44 6@@w(8(<(CD
 
 	Wn555nm44444s   4 AArz   r   c                d   	 |                                  }n$# t          $ r |                                 }Y nw xY w|                    t                    }|5|                    t                    }|                    |j        g           t          |t                    sJ t          |          S r   )r   r   r   rH   r   add_xrecordset_reactorsr   r:   r   r   )rz   r   rS   s      r)   r   r     s    41133 4 4 41133499())D|  !4555<.)))dG$$$$$D!!!s    88RoundtripXRecord | Nonec                    | d S 	 |                                  }n# t          $ r Y d S w xY w|                    t                    }t	          |t
                    rt          |          S d S r   )r   r   rH   r   r:   r   r   )rz   r   xrecords      r)   rQ   rQ     s     t1133   ttii+,,G'7## )(((4s    
))rS   section_namer<   rc   r   c                    |                      |          }|                    d |D                       }t          j        |          S )Nc              3  >   K   | ]}t          |j                  V  d S r   )r   value)r   ts     r)   r   z)get_roundtrip_vertices.<locals>.<genexpr>  s*      #@#@aDMM#@#@#@#@#@#@r*   )get_sectionr^   r   r3   )rS   r   rc   tagsr   s        r)   rb   rb     sI     L))D###@#@4#@#@#@@@H:hr*   verticefloatc                ^    t          |           }|j        r|j        }|j        |j        z  S dS )Nrn   )r   r   r   xy)r   r   r   s      r)   r&   r&     s3    !!D} yv3r*   )r   r   r$   r   )r   r   r   r   r$   r   )r   r
   r$   r@   )r   r
   r$   r	   )rz   r	   r$   r   )rz   r@   r$   r   )rS   r   r   r<   rc   r   r$   r   )r   r   r$   r   ),
__future__r   typingr   r   dataclassesezdxf.lldxfr   ezdxf.lldxf.tagsr   ezdxf.lldxf.typesr   ezdxf.entitiesr	   r
   r   r   r   
ezdxf.mathr   r   r   r   r   r   "ezdxf.entities.acad_xrec_roundtripr   __all__r   r   r   r   r   	dataclassr   r   ra   r   r   ro   r   rQ   rb   r&   r5   r*   r)   <module>r      s   # " " " " " % % % % % % % %           ! ! ! ! ! ! $ $ $ $ $ $ P P P P P P P P P P P P P P H H H H H H H H H H H H H H H H ? ? ? ? ? ?
9
9
9+ ; &K #
 '9 '9 '9 '9 '9 '9 '9 '9TZ4 Z4 Z4 Z4 Z4 Z4 Z4 Z4z3 3 3 3W W W W   "   ,
" 
" 
" 
"               r*   