
    BPcJ                         d Z ddlmZ ddlmZ ddlZddlZddlmZmZmZm	Z	m
Z
mZ ddlmZ dZ G d d	e          ZddZddZ G d dej                  Zedk    r e                                             dS dS )a  
TODO: mark elements that have previously been snapped, along with the settings
    used, so that the same settings can be used for that element next time when
    it's selected as part of a group (and add an option to the extension dialog
    "Use previous/default settings" which is selected by default)

TODO: make elem_offset return [x_offset, y_offset] so we can handle non-symetric scaling
      => will probably need to take into account non-symetric scaling on stroke-widths,
         too (horizontal vs vertical strokes)

TODO: Transforming points isn't quite perfect, to say the least. In particular,
    when translating a point on a bezier curve, we translate the handles by the same amount.
    BUT, some handles that are attached to a particular point are conceptually
    handles of the prev/next node.
    Best way to fix it would be to keep a list of the fractional_offsets[] of
    each point, without transforming anything. Then go through each point and
    transform the appropriate handle according to the relevant fraction_offset
    in the list.

    i.e. calculate first, then modify.

    In fact, that might be a simpler algorithm anyway -- it avoids having
    to keep track of all the first_xy/next_xy guff.

Note: This doesn't work very well on paths which have both straight segments
      and curved segments.
      The biggest three problems are:
        a) we don't take handles into account (segments where the nodes are
           aligned are always treated as straight segments, even where the
           handles make it curve)
        b) when we snap a straight segment right before/after a curve, it
           doesn't make any attempt to keep the transition from the straight
           segment to the curve smooth.
        c) no attempt is made to keep equal widths equal. (or nearly-equal
           widths nearly-equal). For example, font strokes.

Note: Paths that have curves & arcs on some sides of the bounding box won't
    be snapped correctly on that side of the bounding box, and nor will they
    be translated/resized correctly before the path is modified. Doesn't affect
    most applications of this extension, but it highlights the fact that we
    take a geometrically simplistic approach to inspecting & modifying the path.
    )division)print_functionN)PathElementGroupImage	RectangleShapeElement	Transform)inkex_gettext   c                       e Zd ZdS )TransformErrorN)__name__
__module____qualname__     +/usr/share/inkscape/extensions/pixelsnap.pyr   r   N   s        Dr   r   Fc                 6    |r|  } |                      |          S )z#apply_to_point with inbuilt inverse)apply_to_point)	transformptinverses      r   transform_pointr   R   s%     J	##B'''r   c                 `    |r|  } |
|| j         z  }|
|| j        z  }||||fS ||S ||S dS )zDimensions don't get translated. I'm not sure how much diff rotate/skew
    makes in this context, but we currently ignore anything besides scale.
    N)ad)r   widthheightr   s       r   transform_dimensionsr    Y   sj      J	)+V/f} r   c                       e Zd ZdZd Zd Zd ZddZddZd Z	dd	Z
dd
ZddZd ZddZddZddZddZddZd ZdS )	PixelSnapzSnap objects to pixelsc                    |                     ddt          j        dd           |                     ddt          j        dd           |                     d	d
t          dd           |                     dddddgd           dS )zAdd inx optionsz-az--snap_ancestorsTzOSnap unselected ancestors' translations (groups, layers, document height) first)typedefaulthelpz-tz--ancestor_offsetz_Calculate offset relative to unselected ancestors' transforms (includes document height offset)z-gz--max_gradientg      ?z&Maximum slope to consider straight (%)z-sz	--snap_totlblzOrigin of the coordinate system)r%   choicesr&   N)add_argumentinkexBooleanfloat)selfparss     r   add_argumentszPixelSnap.add_argumentsp   s    6 	 	
 	
 	
 	; 	 	
 	
 	
 	9 	 	
 	
 	
 	4L2 	 	
 	
 	
 	
 	
r   c                     t          |d         |d         z
            }t          |d         |d         z
            }|dk    r|dk    rdS |dk    rdS ||z  | j        j        dz  k     S Nr      TFd   )absoptionsmax_gradientr.   pt1pt2hlenvlens        r   verticalzPixelSnap.vertical   sq    3q6CF?##3q6CF?##1994QYY5tt|83>>>r   c                    t          t          |d         |d         z
            t                    }t          t          |d         |d         z
            t                    }|dk    r|dk    rdS |dk    rdS ||z  | j        j        dz  k     S r2   )roundr5   	Precisionr6   r7   r8   s        r   
horizontalzPixelSnap.horizontal   s    SQ#a&))955SQ#a&))9551994QYY5tt|83>>>r   Nc                 T   |                      |          }|dk    rdS |j        t          |          z  }t          t          |j                  t          |j                  z
            dt           z  k    rt          t          d                    t          ||          }|dz  S )zxReturns the amount the bounding-box is offset due to the stroke-width.
        Transform is taken into account.
        r   
   z'Selection contains non-symetric scalingr      )
stroke_widthr   r
   r5   r   r   r@   r   _r    )r.   elemparent_transformrF   r   s        r   stroke_width_offsetzPixelSnap.stroke_width_offset   s     ((..11NY/?%@%@@	s9;#ik"2"2233rI:~FF ;<<   ,I\JJJar   c                     |j         } |d          }d}|r7|5| j                             |d                                                    }|r||d<   dS |S )z-Get/set stroke-width in pixels, untransformedstroker   Nzstroke-width)stylesvgto_dimensionlessstrip)r.   rH   setvalrM   rL   rF   s         r   rF   zPixelSnap.stroke_width   sq    
x 	Tfn844UU>5J5J5P5P5R5RSSL 	 $*E.!!!r   c                    ||         d                                          }|dk    rdS |dk    r;t          |||         d         d         dg          d         ||         d         d<   dS |dk    r;t          |d||         d         d         g          d         ||         d         d<   dS d}|dk    rd}t          |t          ||         d                   d	          D ]g}||         d         |         ||         d         |dz            }}t          |||f          \  }}|||         d         |<   |||         d         |dz   <   hdS )
zHModifies a segment so that every point is transformed, including handlesr   zNhr3   vr   r   rE   )lowerr   rangelen)	r.   r   pathisegtypefirst_coordinatejxys	            r   transform_path_nodezPixelSnap.transform_path_node   sU   q'!*""$$c>>F^^+IQ
1q7IJJ1MDGAJqMMM^^+I471:a=7IJJ1MDGAJqMMM #~~#$ +Sa__a@@ & &Awqz!}d1gajQ&71&y1a&991 !Q
1$%Q
1q5!!	& &r   c                    ||         d                                          }dx}}|dk    rd}|dk    r/|r|d         ||         d         d<   n||         d         d         }n|dk    r/|r|d         ||         d         d<   nt||         d         d         }n_|r5|dk    r/|d         ||         d         d<   |d         ||         d         d<   n(||         d         d         }||         d         d         }|||gS dS )	zReturn the endpoint of the given path segment.
        Inspects the segment type to know which elements are the endpoints.
        r   rS   rT   r3   rU   N)rV   )r.   rY   rZ   rQ   r[   r^   r_   s          r   pathxyzPixelSnap.pathxy   s    q'!*""$$	Ac>>Ac>> " &q	Q
1GAJqM^^ " &q	Q
1GAJqM #'S..!'Q
2!'Q
2GAJrNGAJrN>q6M >r   c                    |j                                         }|j        t          |          z  }|                                }|j        r|j        sd S |j        |j        }}|j        |j        }	}t          |          |z  t          |          |z  f}
t          ||d          }t          ||	d          }	t          t          |                    D ]f}t          |          }|                     | ||           |                     t          |
          ||           |                     |||           g||_         d S )NTr   	translate)scale)original_path	to_arraysr   r
   bounding_boxr   r   minimummaximumr?   r   rW   rX   r`   )r.   rH   rI   rY   r   bboxr   r   min_xymax_xyrescalerZ   rh   s                r   snap_path_scalezPixelSnap.snap_path_scale   sK   !++--NY/?%@%@@	  ""
 z 	 	F
DKvt|,,&f(>> FDAAA FDAAAs4yy!! 	9 	9A!F333I$$iZq999$$YW%=%=%=tQGGG$$Ya8888!r   c                    |j                                         }|j        t          |          z  }|                                }|j        |j        }}|d         t          |d                   z
  |d         t          |d                   z
  | j        z
  f}t          ||d         |d         d          }t          t          |                    D ](}	|                     t          |           ||	           )t          t          j        |                    }|                    d          r|                    d|           d S |                    d|           d S )Nr   r3   Trf   rg   zinkscape:original-dr   )rj   rk   r   r
   rl   rm   rn   r?   document_offsetr    rW   rX   r`   strr+   Pathgetset)
r.   rH   rI   rY   r   ro   rp   rq   fractional_offsetrZ   s
             r   snap_path_poszPixelSnap.snap_path_pos  sd   !++--NY/?%@%@@	  ""t| 1IfQi(((1IfQi(((4+??
 1(+->q-A4
 
 
 s4yy!! 	W 	WA$$i:K&L&L&L%LdTUVVVV5:d##$$88)** 	 HH*D11111HHS$r   c                 @   |j         }|j        s|j        rt          t	          d                    t          |                                          }t          |j                  |d<   t          |j	                  |d<   |xj         t          |          z  c_         d S )Nz9TR: Selection contains transformations with skew/rotation   r   )r   cbr   rG   listto_hexadr?   efr
   )r.   rH   r   trms       r   snap_transformzPixelSnap.snap_transform*  s     N	; 	)+ 	 MNN   9%%''((y{##Ay{##A)C..(r   c                    |j         t          |          z  }|                     |          }|dk    rd S t          t          |j                  t          |j                  z
            dt           z  k    rt          t          d                    |rJt          ||          }t          |          }t          ||d          }|                     ||           d S d S )Nr   rC   z@Selection contains non-symetric scaling, can't snap stroke widthrD   T)r   r   )r   r
   rF   r5   r   r   r@   r   rG   r    r?   )r.   rH   rI   r   rF   s        r   snap_strokezPixelSnap.snap_stroke:  s    NY/?%@%@@	((..1Fs9;#ik"2"2233rI:~FF TUU    	2/	NNNL ..L/t  L dL11111	2 	2r   c                 N   |j                                         }|j        t          |          z  }|j        s|j        rt          t          d                    |                     ||          dz  }| 	                    |d          }| 	                    |d          }t          t          |                    D ]`}||         d                                         }	| 	                    ||          }
|	dk    r|}
|t          |          dz
  k    s:|t          |          dz
  k    r'|d         d                                         dk    r|}n| 	                    ||dz             }|
r|r|s|
}t          |
          }t          t          ||
                    }
t          ||          }t          ||          }dx}}|                     |
|          r&t          |          dk    s|dk    r|d         |
d<   d}|                     |
|          rd}|                     |
|          r&t          |          dk    s|dk    r|d         |
d<   d}|                     |
|          rd}t          |          }ddg}|r'|
d         t%          |
d         |z
            |z   z
  |d<   |r/|
d         t%          |
d         |z
            |z   z
  | j        z
  |d<   t)          ||d         |d         d	          }|                     t          |
           ||           b||_         d S )Nz;Path: Selection contains transformations with skew/rotationr3   rc   r   rS   rE   FTrf   rg   )rj   rk   r   r
   r~   r   r   rG   rJ   rd   rW   rX   rV   tupler   r   rA   r=   r?   ru   r    r`   )r.   rH   rI   rY   r   offsetprev_xyfirst_xyrZ   r[   xynext_xyxy_untransformedon_verticalon_horizontalrz   s                   r   	snap_pathzPixelSnap.snap_pathN  sg   !++--NY/?%@%@@	; 	)+ 	 OPP   ))$0@AAAE++dB'';;tQ''s4yy!! 4	W 4	WA1gaj&&((GT1%%B#~~SYY]""c$ii!m##b!):):)<)<)C)C"++dAE22 7 w $Ryyoi4455B%i99G%i99G*//K-r7++ %t99q==AFF#AJBqE $r7++ % $}}R)) #t99q==AFF#AJBqE"}}R)) #",--G!"A P')!ubefn0E0E0N'O!!$ qEU2a56>22V;<t?SS "!$ !5,Q/1B11Et! ! ! $$i:K&L&L&L%LdTUVVVV!r   c                    |j         t          |          z  }|j        s|j        rt	          t          d                    |                     ||          dz  }| j                            |j	        d                   }| j                            |j	        d                   }| j                            |j	        d                   }| j                            |j	        d                   }t          |||          \  }}t          |||g          \  }}t          |          }t          |          }t          ||z
            |z   }t          ||z
            |z   }t          |||d          \  }}t          |||gd          \  }}|| j        |j        z  z  }t          |          |j	        d<   t          |          |j	        d<   t          |          |j	        d<   t          |          |j	        d<   d S )	Nz;Rect: Selection contains transformations with skew/rotationr3   r   r   r^   r_   Trf   )r   r
   r~   r   r   rG   rJ   rN   rO   attribr    r   r?   ru   r   rv   )	r.   rH   rI   r   r   r   r   r^   r_   s	            r   	snap_rectzPixelSnap.snap_rect  s   NY/?%@%@@	; 	)+ 	 OPP   ))$0@AAAE))$+g*>??**4;x+@AAH%%dk#&677H%%dk#&677,YvFFvy1a&111 ve!f*& 	
 !f*&,YvtTTTvy1a&$???1	T!IK//  #5zzG #FHq66Cq66Cr   c                 2    |                      ||           d S N)r   )r.   rH   rI   s      r   
snap_imagezPixelSnap.snap_image  s    t-.....r   c                    t          |t          t          t          t          f          sd S t          |t                    r}|                     |           |j        t          |          z  }|D ]L}	 |                     ||           # t          $ r&}t          j        t          |                    d }~ww xY wd S | j        j        r.|,|                                D ]}|                     |           | j        j        rO|Mt          |                                t$                    r&|                                                                }|                     |           	 |                     ||           n3# t          $ r&}t          j        t          |                    d }~ww xY wt          |t                    rD|                     ||           |                     ||           |                     ||           d S t          |t                    r|                     ||           d S t          |t                    r|                     ||           d S d S r   )
isinstancer   r   r   r   r   r   r
   
pixel_snapr   r+   AbortExtensionrv   r6   snap_ancestors	ancestorsancestor_offset	getparentr	   composed_transformr   rs   r{   r   r   r   )r.   rH   rI   r   childerrs         r   r   zPixelSnap.pixel_snap  s   $y+ FGG 	FdE"" 	%%%3C)D)DDI 9 99OOE95555% 9 9 9.s3xx8889F <& 	++;+C)) + +##E**** <' 	I,<,D$..**L99 I#'>>#3#3#F#F#H#H D!!!	1T#34444 	1 	1 	1&s3xx000	1 dK(( 		4  '7888t%5666NN&     i(( 	4NN4!122222e$$ 	4OOD"233333	4 	4s0   1B
B8!B33B8(E? ?
F/	!F**F/c                    | j         j        dk    r@| j                            | j                                        d                   dz  | _        nd| _        | j        j                                        D ]N\  }}	 |                     |           # t          $ r&}t          j        t          |                    d }~ww xY wd S )Nr(      r3   r   )r6   snap_torN   rO   get_viewboxru   	selectionitemsr   r   r+   r   rv   )r.   idrH   r   s       r   effectzPixelSnap.effect  s    <4''))$(*>*>*@*@*CDDqH    $%D *0022 	5 	5HB5%%%%! 5 5 5*3s884445	5 	5s   <B
C!B==Cr   )r   r   r   __doc__r0   r=   rA   rJ   rF   r`   rd   rs   r{   r   r   r   r   r   r   r   r   r   r   r"   r"   m   sE         
 
 
B? ? ?? ? ?       &       & & &(   @" " " "6       .) ) ) 2 2 2 2(D" D" D" D"L"" "" "" ""H/ / / /)4 )4 )4 )4V5 5 5 5 5r   r"   __main__)F)NNF)r   
__future__r   r   sysr+   r   r   r   r   r	   r
   inkex.localizationr   rG   r@   	Exceptionr   r   r    EffectExtensionr"   r   runr   r   r   <module>r      sH  .) )V        % % % % % % 



  O O O O O O O O O O O O O O O O 1 1 1 1 1 1		 	 	 	 	Y 	 	 	( ( ( (   (D5 D5 D5 D5 D5% D5 D5 D5N zIKKOO r   