
    'j7L                    0   U d dl mZ d dlmZmZmZmZmZmZm	Z	m
Z
 d dlmZmZ d dlZd dlZd dlmZmZ d dlmZmZ d dlmZmZ dd	lmZ dd
lmZmZmZmZ ddl m!Z! ddl"m#Z# ddgZ$dZ% G d de          Z&dZ'dZ(dZ)dZ*dZ+ G d de&          Z,ed=d>d            Z-ee.e/e.gee.ef         f         Z0de1d<   eege
e/e/f         f         Z2de1d <   e	e
e/e/f                  Z3de1d!<   e	e3         Z4de1d"<   d?d)Z5d@d-Z6dAdBd0Z7 G d1 de&          Z8dCd5Z9dDd:Z:dEd<Z;dS )F    )annotations)IterableSequenceno_type_checkAnyCallableDictListTuple)	TypeAliasoverrideN)Vec2world_mercator_to_gps)Commandnesting)orient_pathssingle_paths   )Color)BackendInterfaceBkPath2d
BkPoints2d	ImageData)Configuration)BackendPropertiesCustomJSONBackendGeoJSONBackenda~  
JSON content = [entity, entity, ...]

entity = {
    "type": point | lines | path | filled-paths | filled-polygon,
    "properties": {
        "color": "#RRGGBBAA",
        "stroke-width": 0.25, # in mm
        "layer": "name"
    },
    "geometry": depends on "type"
}
DXF linetypes (DASH, DOT, ...) are resolved into solid lines.

A single point:
point = {
    "type": "point",
    "properties": {...},
    "geometry": [x, y]
}

Multiple lines with common properties:
lines = {
    "type": "lines",
    "properties": {...},
    "geometry": [
        (x0, y0, x1, y1),  # 1. line
        (x0, y0, x1, y1),  # 2. line
        ....
    ]
}
Lines can contain points where x0 == x1 and y0 == y1!

A single linear path without filling:
path = {
    "type": "path",
    "properties": {...},
    "geometry": [path-command, ...]
}

SVG-like path structure:
- The first path-command is always an absolute move to "M"
- The "M" command does not appear inside a path, each path is a continuouse geometry 
  (no multi-paths).

path-command = 
    ("M", x, y) = absolute move to
    ("L", x, y) = absolute line to
    ("Q", x0, y0, x1, y1) = absolute quadratice Bezier curve to
    - (x0, y0) = control point
    - (x1, y1) = end point
    ("C", x0, y0, x1, y1, x2, y2) = absolute cubic Bezier curve to
    - (x0, y0) = control point 1
    - (x1, y1) = control point 2
    - (x2, y2) = end point
    ("Z",) = close path

Multiple filled paths:

Exterior paths and holes are mixed and NOT oriented by default (clockwise or 
counter-clockwise) - PyQt and SVG have no problem with that structure but matplotlib 
requires oriented paths.  When oriented paths are required the CustomJSONBackend can 
orient the paths on demand.

filled-paths = {
    "type": "filled-paths",
    "properties": {...},
    "geometry": [
        [path-command, ...],  # 1. path
        [path-command, ...],  # 2. path  
        ...
    ]
}

A single filled polygon:
A polygon is explicitly closed, so first vertex == last vertex is guaranteed.
filled-polygon = {
    "type": "filled-polygon",
    "properties": {...},
    "geometry": [
        (x0, y0),
        (x1, y1),
        (x2, y2),
        ...
    ]
}

c                      e Zd ZddZej        dd            ZddddZedd            Z	edd            Z
ed d            Zed!d            Zedd            Zedd            Zedd            ZdS )"_JSONBackendreturnNonec                L    g | _         d| _        d| _        d| _        d| _        d S )Ng{Gz?皙?g      ?        )	_entitiesmax_sagittamin_lineweightlineweight_scalingfixed_lineweightselfs    S/DATA/AppData/hermes/venv/lib/python3.11/site-packages/ezdxf/addons/drawing/json.py__init__z_JSONBackend.__init__p   s1    /1""% !$    r   c                    d S N r*   s    r,   get_json_dataz_JSONBackend.get_json_dataz   s    $'Cr.      indentr5   	int | strstrc               R    t          j        |                                 |          S )z$Returns the result as a JSON string.r4   )jsondumpsr2   )r+   r5   s     r,   
get_stringz_JSONBackend.get_string|   s#    z$,,..v>>>>r.   configr   c                    |j         r"|j         dz  dz  }t          d|          | _         |j        | _        | j        dk    r| j         | _        |j        | _        d S )Ngffffff9@i,  r#   r$   )r'   maxr(   r)   max_flattening_distancer&   )r+   r<   min_lineweight_mms      r,   	configurez_JSONBackend.configure   sh      	? & 5 <s B"%d,=">">D"(";"c))$($7D!!9r.   c                8    | j                                          d S r0   )r%   clearr*   s    r,   rC   z_JSONBackend.clear   s    r.   
image_datar   
propertiesr   c                    d S r0   r1   )r+   rD   rE   s      r,   
draw_imagez_JSONBackend.draw_image       r.   colorr   c                    d S r0   r1   )r+   rI   s     r,   set_backgroundz_JSONBackend.set_background   rH   r.   c                    d S r0   r1   r*   s    r,   finalizez_JSONBackend.finalize   rH   r.   c                    d S r0   r1   )r+   entityrE   s      r,   enter_entityz_JSONBackend.enter_entity   rH   r.   c                    d S r0   r1   )r+   rO   s     r,   exit_entityz_JSONBackend.exit_entity   rH   r.   Nr    r!   )r    r   )r5   r6   r    r7   )r<   r   r    r!   )rD   r   rE   r   r    r!   )rI   r   r    r!   )__name__
__module____qualname__r-   abcabstractmethodr2   r;   r   rA   rC   rG   rK   rM   rP   rR   r1   r.   r,   r   r   o   sE       $ $ $ $ 	''' '01 ? ? ? ? ? ? 	: 	: 	: X	:    X    X    X    X    X    X  r.   r   MLQCZc                       e Zd ZdZd#d$ fdZed%d            Zd&dZd'dZed(d            Z	ed)d            Z
ed*d            Zed+d            Zed,d            Zed-d"            Z xZS ).r   a  Creates a JSON-like output with a custom JSON scheme.  This scheme supports
    curved shapes by a SVG-path like structure and coordinates are not limited in
    any way.  This backend can be used to send geometries from a web-backend to a
    frontend.

    The JSON scheme is documented in the source code:

    https://github.com/mozman/ezdxf/blob/master/src/ezdxf/addons/drawing/json.py

    Args:
        orient_paths: orient exterior and hole paths on demand, exterior paths have
            counter-clockwise orientation and holes have clockwise orientation.

    **Class Methods**

    .. automethod:: get_json_data

    .. automethod:: get_string

    .. versionadded:: 1.3.0

    Fr    r!   c                V    t                                                       || _        d S r0   )superr-   r   )r+   r   	__class__s     r,   r-   zCustomJSONBackend.__init__   s'    (r.   list[dict[str, Any]]c                    | j         S )z1Returns the result as a JSON-like data structure.)r%   r*   s    r,   r2   zCustomJSONBackend.get_json_data   s     ~r.   entity_typer7   geometrySequence[Any]rE   r   c                p    |sd S | j                             ||                     |          |d           d S )NtyperE   re   )r%   appendmake_properties_dict)r+   rd   re   rE   s       r,   
add_entityzCustomJSONBackend.add_entity   sV      	F#"77
CC$ 	
 	
 	
 	
 	
r.   dict[str, Any]c                    | j         r| j         }n"t          | j        |j        | j        z            }|j        t          |d          |j        dS )Nr3   rI   zstroke-widthlayerr)   r>   r'   
lineweightr(   rI   roundrp   r+   rE   stroke_widths      r,   rk   z&CustomJSONBackend.make_properties_dict   sc      	0LL#Z%:T=T%T L  %!,22%
 
 	
r.   posr   c                L    |                      d|j        |j        g|           d S )Npointrl   xyr+   rv   rE   s      r,   
draw_pointzCustomJSONBackend.draw_point   s&    #%<<<<<r.   startendc                f    |                      d|j        |j        |j        |j        fg|           d S )Nlinesry   )r+   r~   r   rE   s       r,   	draw_linezCustomJSONBackend.draw_line   s2    57EGSUCE"B!CZPPPPPr.   r   Iterable[tuple[Vec2, Vec2]]c                    t          |          }t          |          dk    rd S |                     dd |D             |           d S )Nr   r   c                H    g | ]\  }}|j         |j        |j         |j        f S r1   rz   r{   ).0ses      r,   
<listcomp>z6CustomJSONBackend.draw_solid_lines.<locals>.<listcomp>   s-    !I!I!I41a13QS!#"6!I!I!Ir.   )listlenrl   )r+   r   rE   s      r,   draw_solid_linesz"CustomJSONBackend.draw_solid_lines   sN     Uu::??F!I!I5!I!I!I:VVVVVr.   pathr   c                N    |                      dt          |          |           d S )Nr   )rl   make_json_path)r+   r   rE   s      r,   	draw_pathzCustomJSONBackend.draw_path   s&    t 4 4jAAAAAr.   pathsIterable[BkPath2d]c                D   t          |          }t          |          dk    rd S | j        rt          |          }nt          |          }g }|D ]5}t          |          r$|                    t          |d                     6|r|                     d||           d S d S )Nr   T)closezfilled-paths)r   r   r   r   rj   r   rl   )r+   r   rE   
json_pathsr   s        r,   draw_filled_pathsz#CustomJSONBackend.draw_filled_paths   s     Uu::??F 	( ''EE !''E "
 	D 	DD4yy D!!.T"B"B"BCCC 	DOONJ
CCCCC	D 	Dr.   pointsr   c                   |                                 }t          |          dk     rd S |d                             |d                   s|                    |d                    |                     dd |D             |           d S )N   r   zfilled-polygonc                *    g | ]}|j         |j        fS r1   r   )r   vs     r,   r   z9CustomJSONBackend.draw_filled_polygon.<locals>.<listcomp>  s     *H*H*H!AC:*H*H*Hr.   )verticesr   iscloserj   rl   )r+   r   rE   r   s       r,   draw_filled_polygonz%CustomJSONBackend.draw_filled_polygon  s      &00x==1F{""8B<00 	)OOHQK((((*H*Hx*H*H*H*UUUUUr.   FrS   )r    rb   )rd   r7   re   rf   rE   r   )rE   r   r    rm   rv   r   rE   r   r    r!   r~   r   r   r   rE   r   r    r!   r   r   rE   r   r    r!   r   r   rE   r   r    r!   r   r   rE   r   r    r!   r   r   rE   r   r    r!   )rT   rU   rV   __doc__r-   r   r2   rl   rk   r}   r   r   r   r   r   __classcell__ra   s   @r,   r   r      sl        .) ) ) ) ) ) )    X
 
 
 

 
 
 
 = = = X= Q Q Q XQ W W W XW B B B XB D D D XD$ V V V XV V V V Vr.   Fr   r   r    	list[Any]c           
     8   t          |           dk    rg S | j        }t          |j        |j        fg}|                                 D ]6}|j        }|j        t          j	        k    r(|
                    t          |j        |j        f           G|j        t          j        k    r(|
                    t          |j        |j        f           |j        t          j        k    r;|j        }|
                    t          |j        |j        |j        |j        f           |j        t          j        k    rM|j        }|j        }|
                    t&          |j        |j        |j        |j        |j        |j        f           8|r|
                    t(                     |S )Nr   )r   r~   MOVE_TO_ABSrz   r{   commandsr   ri   r   MOVE_TOrj   LINE_TOLINE_TO_ABS	CURVE3_TOctrlQUAD_TO_ABS	CURVE4_TOctrl1ctrl2CUBIC_TO_ABS
CLOSE_PATH)r   r   r   r   cmdc1c2s          r,   r   r     sX   
4yyA~~	
C"CE3512H}} R Rg8w&&OO[#%78888X((OO[#%78888X***BOO["$ceSUCDDDDX***BBOO\24rtRT35#%PQQQ $
###Or.   r   PropertiesMakerTransformFuncRingGeoJsonPolygonrI   r7   ru   floatrp   rm   c                *    | t          |d          |dS )a  Returns the property dict::

        {
            "color": color,
            "stroke-width": stroke_width,
            "layer": layer,
        }

    Returning an empty dict prevents properties in the GeoJSON output and also avoids
    wraping entities into "Feature" objects.
    r3   ro   )rs   )rI   ru   rp   s      r,   properties_makerr   >  s&     lA..  r.   locationr   tuple[float, float]c                    | j         | j        fS )zsDummy transformation function.  Does not apply any transformations and
    just returns the input coordinates.
    r   )r   s    r,   no_transformr   Q  s     J
##r.   ư>tolc                     d fd}|S )aG  Returns a function to transform WGS84 World Mercator `EPSG:3395 <https://epsg.io/3395>`_
    location given as cartesian 2D coordinates x, y in meters into WGS84 decimal
    degrees as longitude and latitude `EPSG:4326 <https://epsg.io/4326>`_ as
    used by GPS.

    Args:
        tol: accuracy for latitude calculation

    r   r   r    r   c                :    t          | j        | j                  S )zITransforms WGS84 World Mercator EPSG:3395 coordinates to WGS84 EPSG:4326.)r   rz   r{   )r   r   s    r,   
_transformz7make_world_mercator_to_gps_function.<locals>._transformc  s    $XZSAAAr.   r   r   r    r   r1   )r   r   s   ` r,   #make_world_mercator_to_gps_functionr   X  s/    B B B B B B r.   c                       e Zd ZdZeefd# fdZed$d
            Zd%dZ	d&dZ
ed'd            Zed(d            Zed)d            Zed*d            Zed+d            Zed,d"            Z xZS )-r   a1  Creates a JSON-like output according the `GeoJSON`_ scheme.
    GeoJSON uses a geographic coordinate reference system, World Geodetic
    System 1984 `EPSG:4326 <https://epsg.io/4326>`_, and units of decimal degrees.

    - Latitude: -90 to +90 (South/North)
    - Longitude: -180 to +180 (East/West)

    So most DXF files will produce invalid coordinates and it is the job of the
    **package-user** to provide a function to transfrom the input coordinates to
    EPSG:4326!  The :class:`~ezdxf.addons.drawing.recorder.Recorder` and
    :class:`~ezdxf.addons.drawing.recorder.Player` classes can help to detect the
    extents of the DXF content.

    Default implementation:

    .. autofunction:: no_transform

    Factory function to make a transform function from WGS84 World Mercator
    `EPSG:3395 <https://epsg.io/3395>`_  coordinates to WGS84 (GPS) 
    `EPSG:4326 <https://epsg.io/4326>`_.

    .. autofunction:: make_world_mercator_to_gps_function

    The GeoJSON format supports only straight lines so curved shapes are flattened to
    polylines and polygons.

    The properties are handled as a foreign member feature and is therefore not defined
    in the GeoJSON specs.  It is possible to provide a custom function to create these
    property objects.

    Default implementation:

    .. autofunction:: properties_maker


    Args:
        properties_maker: function to create a properties dict.

    **Class Methods**

    .. automethod:: get_json_data

    .. automethod:: get_string

    .. versionadded:: 1.3.0
    
    .. _GeoJSON: https://geojson.org/
    r   r   transform_funcr   r    r!   c                d    t                                                       || _        || _        d S r0   )r`   r-   _properties_dict_maker_transform_function)r+   r   r   ra   s      r,   r-   zGeoJSONBackend.__init__  s1    
 	&6##1   r.   rm   c                    t          | j                  dk    ri S | j        d         d         dk    }|r
d| j        dS d| j        dS )zMReturns the result as a JSON-like data structure according the GeoJSON specs.r   ri   FeatureFeatureCollection)ri   featuresGeometryCollection)ri   
geometries)r   r%   )r+   using_featuress     r,   r2   zGeoJSONBackend.get_json_data  s]     t~!##I*62i? 	P/T^LLL0OOOr.   rO   rE   r   c                    |sd S  | j         |                     |           }|r | j                            d||d           d S | j                            |           d S )Nr   rh   )r   make_propertiesr%   rj   )r+   rO   rE   properties_dicts       r,   rl   zGeoJSONBackend.add_entity  s     	F*E$*E!!*--+
  		*N!!%"1 &      N!!&)))))r.   tuple[str, float, str]c                    | j         r| j         }n"t          | j        |j        | j        z            }|j        t          |d          |j        fS )Nr3   rq   rt   s      r,   r   zGeoJSONBackend.make_properties  sX      	0LL#Z%:T=T%T L  %a"8"8*:JKKr.   rv   r   c           
         |                      t          dt          |                     |                              |           d S )NPoint)rl   geojson_objectr   r   r|   s      r,   r}   zGeoJSONBackend.draw_point  sG    7D)A)A#)F)F$G$GHH*	
 	
 	
 	
 	
r.   r~   r   c           	         | j         }|                     t          d ||           ||          g          |           d S )N
LineString)r   rl   r   )r+   r~   r   rE   tfs        r,   r   zGeoJSONBackend.draw_line  sO    %<""U))RRWW)=>>	
 	
 	
 	
 	
r.   r   r   c                    t          |          }t          |          dk    rd S | j        fd|D             }|                     t	          d|          |           d S )Nr   c                B    g | ]\  }} |           |          fS r1   r1   )r   r   r   r   s      r,   r   z3GeoJSONBackend.draw_solid_lines.<locals>.<listcomp>  s1    777Arr!uubbeen777r.   MultiLineString)r   r   r   rl   r   )r+   r   rE   
json_linesr   s       @r,   r   zGeoJSONBackend.draw_solid_lines  sj     Uu::??F%7777777
'8*EEzRRRRRr.   r   r   c                    t          |          dk    rd S | j        fd|                    | j                  D             }|                     t          d|          |           d S )Nr   c                &    g | ]} |          S r1   r1   r   r   r   s     r,   r   z,GeoJSONBackend.draw_path.<locals>.<listcomp>  s!    NNNaBBqEENNNr.   )distancer   )r   r   
flatteningr&   rl   r   )r+   r   rE   r   r   s       @r,   r   zGeoJSONBackend.draw_path  sm    t99>>F%NNNN4??D<L?#M#MNNN|X>>
KKKKKr.   r   r   c                (   t          |          }t          |          dk    rd S g }|D ]@}t          |          r/|                    t          || j        | j                             A|r&|                     t          d|          |           d S d S )Nr   )r&   r   MultiPolygon)r   r   extendgeojson_polygonsr&   r   rl   r   )r+   r   rE   polygonsr   s        r,   r   z GeoJSONBackend.draw_filled_paths  s     Uu::??F)+ 	 	D4yy $$*:t?W    
  	ROON>8DDjQQQQQ	R 	Rr.   r   r   c                B   |                                 }t          |          dk     rd S |d                             |d                   s|                    |d                    | j        |                     t          dfd|D             g          |           d S )Nr   r   r   Polygonc                &    g | ]} |          S r1   r1   r   s     r,   r   z6GeoJSONBackend.draw_filled_polygon.<locals>.<listcomp>	  s!    '@'@'@!1'@'@'@r.   )r   r   r   rj   r   rl   r   )r+   r   rE   r   r   s       @r,   r   z"GeoJSONBackend.draw_filled_polygon  s      &00x==1F{""8B<00 	)OOHQK(((%9'@'@'@'@x'@'@'@&ABBJ	
 	
 	
 	
 	
r.   )r   r   r   r   r    r!   )r    rm   )rO   rm   rE   r   )rE   r   r    r   r   r   r   r   r   r   )rT   rU   rV   r   r   r   r-   r   r2   rl   r   r}   r   r   r   r   r   r   r   s   @r,   r   r   i  sq       / /f -=(42 2 2 2 2 2 2 P P P XP* * * *"L L L L 
 
 
 X

 
 
 
 X
 S S S XS L L L XL R R R XR$ 
 
 
 X
 
 
 
 
r.   namecoordinatesr   c                    | |dS )N)ri   r   r1   )r   r   s     r,   r   r     s    555r.   is_holeboolr&   r   c                .   | j         rt          d          fd|                     |          D             }| j        s%| j        }|                     |                     |                                 }|r|r|s|r|                                 |S )a#  Returns a linear ring according to the GeoJSON specs.

    -  A linear ring is a closed LineString with four or more positions.
    -  The first and last positions are equivalent, and they MUST contain
       identical values; their representation SHOULD also be identical.
    -  A linear ring is the boundary of a surface or the boundary of a
       hole in a surface.
    -  A linear ring MUST follow the right-hand rule with respect to the
       area it bounds, i.e., exterior rings are counterclockwise, and
       holes are clockwise.

    zmulti-paths not allowedc                &    g | ]} |          S r1   r1   r   s     r,   r   z geojson_ring.<locals>.<listcomp>"  s!    BBBbbeeBBBr.   )has_sub_paths	TypeErrorr   	is_closedr~   rj   has_clockwise_orientationreverse)r   r   r&   r   r   r~   	clockwises      `   r,   geojson_ringr    s      31222BBBBT__[%A%ABBBH> #
5		"""..00I 	 7 y Or.   list[GeoJsonPolygon]c           
        |                                  }t          |          dk    rg S t          |          dk    rt          |d         d||          ggS t          j        |          }g }|D ]}t          |d         d||          g}t          |          dk    r|d         }t          |t                    r&|                    t          |d||                     qt          |t          t          f          rN|D ]K}	t          |	t          t          f          r|	d         }	|                    t          |	d||                     L|                    |           |S )zReturns a list of polygons, where each polygon is a list of an exterior path and
    optional holes e.g. [[ext0, hole0, hole1], [ext1], [ext2, hole0], ...].

    r   r   FT)
	sub_pathsr   r  r   make_polygon_structure
isinstancer   rj   tupler   )
r   r&   r   r  r   r   polygongeojson_polygonholesholes
             r,   r   r   ,  sx    !% 0 0I
9~~	
9~~ilE;CCDEE-i88H-/ 1 1UK<<+
 w<<! AJE%** &&|E4b'Q'QRRR%%// V! V VD!$66 '#Aw#**<dKQS+T+TUUUU0000r.   r   )r   r   r    r   )rI   r7   ru   r   rp   r7   r    rm   r   )r   )r   r   r    r   )r   r7   r   r   r    rm   )
r   r   r   r   r&   r   r   r   r    r   )r   r   r&   r   r   r   r    r  )<
__future__r   typingr   r   r   r   r   r	   r
   r   typing_extensionsr   r   rW   r9   
ezdxf.mathr   r   
ezdxf.pathr   r   ezdxf.npshapesr   r   
type_hintsr   backendr   r   r   r   r<   r   rE   r   __all__CUSTOM_JSON_SPECSr   r   r   r   r   r   r   r   r7   r   r   __annotations__r   r   r   r   r   r   r   r   r  r   r1   r.   r,   <module>r     s$   # " " " " " " V V V V V V V V V V V V V V V V V V V V 1 1 1 1 1 1 1 1 



  2 2 2 2 2 2 2 2 ' ' ' ' ' ' ' ' 5 5 5 5 5 5 5 5       F F F F F F F F F F F F ! ! ! ! ! ! ) ) ) ) ) )  0
1W t3 3 3 3 3# 3 3 3l 
lV lV lV lV lV lV lV lV^     0 &sE3&7c3h&GH H H H H#TFE%,,?$?@ @ @ @ @uUE\*+ + + + + !J & & & &   &$ $ $ $    "a
 a
 a
 a
 a
\ a
 a
 a
H6 6 6 6   6" " " " " "r.   