# Best way to draw scaled polygons in tikz

I want to draw pictures like this

or this one

.

It is clear how to do this "manually" with TikZ. However is there a way to do it automatically. I.e. I just want to define the polygon (for example the yellow triangles in the pictures above), a center point Z and a scaling factor m and then get the corresponding picture (as in my examples) automatically generated by that input data.

-
Why the downvote? –  student Sep 16 '12 at 10:51
I assume it is because you didn't show what you've tried so far. This might be seen as a draw-this-for-me question. –  Jake Sep 16 '12 at 18:39

Here is a general solution... but not completely since it can not manage the content of nodes (see below for a simpler solution but less general).

I create a new homothety option usable with a path. This options can store the result of an homothetic transformation applied to this path. Some subkeys control the parameters:

• scale is used to specify the scale (default value: 1).
• center is used to specify the center (default value: {0,0}).
• store in is used to specify the macro that stores the transformed path.
• name is a prefix to name each vertex of the transformed path (default value: homothety).

A little example to show the syntax

\draw[homothety={scale=2,center={1,1},name=A,store in=\transpath}] (0,0) -- (3,4);


As usual, the path is drawn. But in addition:

• A new path (the original path transformed by the homothety whose scale is 2 and center is (1,1)) is stored in \transpath macro.
• The vertices of this new path are A-1, A-2, etc.
• The homothetypoints counter gives the number of vertices.

Then, to draw the transformed path with labels, you can use:

\draw \transpath;
\foreach \num in {1,...,\arabic{homothetypoints}}{
\node[below] (A-\num) {$A_\num$};
}


Strengths and limitations

• You can use homothety just to copy a path (with scale=1 and center={0,0}).
• The original path can use nodes, coordinates, holes in its definition.
• Each vertex of the transformed path is stored.
• But, the content of a node is not transformed...

A larger example (result)

A larger example (long commented code)

\documentclass[margin=5mm]{standalone}
\usepackage{tikz}
\usetikzlibrary{calc,decorations.pathreplacing,decorations.pathmorphing}

\makeatletter
% to produce automaticaly homothetic paths
\newcounter{homothetypoints} % number of vertices of path
\tikzset{
% homothety is a family...
homothety/.style={homothety/.cd,#1},
% ...with some keys
homothety={
% parameters
scale/.store in=\homothety@scale,% scale of current homothetic transformation
center/.store in=\homothety@center,% center of current homothetic transformation
name/.store in=\homothety@name,% prefix for named vertices
% default values
scale=1,
center={0,0},
name=homothety,
% initialization
init memoize homothetic path/.code={
\xdef#1{}
\setcounter{homothetypoints}{0}
},
% incrementation
% a style to store an homothetic transformation of current path into #1 macro
store in/.style={
init memoize homothetic path=#1,
/tikz/postaction={
decorate,
decoration={
show path construction,
moveto code={
% apply homothetic transformation to this segment and add result to #1
\xdef#1{#1 ($(\homothety@center)!\homothety@scale!(\tikzinputsegmentfirst)$)}
% name this vertex
\coordinate[homothety/++](\homothety@name-\arabic{homothetypoints})
at ($(\homothety@center)!\homothety@scale!(\tikzinputsegmentfirst)$);
},
lineto code={
% apply homothetic transformation to this segment and add result to #1
\xdef#1{#1 -- ($(\homothety@center)!\homothety@scale!(\tikzinputsegmentlast)$)}
% name this vertex
\coordinate[homothety/++] (\homothety@name-\arabic{homothetypoints})
at ($(\homothety@center)!\homothety@scale!(\tikzinputsegmentlast)$);
},
curveto code={
% apply homothetic transformation to this segment and add result to #1
\xdef#1{#1
.. controls ($(\homothety@center)!\homothety@scale!(\tikzinputsegmentsupporta)$)
and ($(\homothety@center)!\homothety@scale!(\tikzinputsegmentsupportb)$)
.. ($(\homothety@center)!\homothety@scale!(\tikzinputsegmentlast)$)}
% name this vertex
\coordinate[homothety/++] (\homothety@name-\arabic{homothetypoints})
at ($(\homothety@center)!\homothety@scale!(\tikzinputsegmentlast)$);
},
closepath code={
% apply homothetic transformation to this segment and add result to #1
\xdef#1{#1 -- cycle ($(\homothety@center)!\homothety@scale!(\tikzinputsegmentlast)$)}
},
},
},
},
},
}
\makeatother

\begin{document}
\begin{tikzpicture}[font=\bfseries\sffamily]

% some styles
\tikzset{
dashed line/.style={draw=#1!50!gray,dashed,line width=.4pt},
filled shape/.style={draw=black,line width=1pt,fill=#1,fill opacity=.4},
dot/.style={draw,line width=.4pt,fill=#1!50!gray},
}

% draw a path (and memomize its definition into \mypath with points named A-1, A-2,...)
\draw[filled shape=cyan,homothety={store in=\mypath,name=A}]
(0,0) to[bend right] ++(2,2) -- ++(-1,1) to[bend left] ++(-2,-2) -- cycle;

% add a label to each vertex
\pgfmathsetmacro{\nbpoints}{\arabic{homothetypoints}}
\foreach \num in {1,...,\nbpoints} {
\node[above] at (A-\num) {$A_\num$};
}
% first center: c1
\fill[dot=green] (0,3) coordinate (c1) circle(2pt) node[right]{$c_1$};
% store two homothetic transformations of \mypath
\path[homothety={store in=\secondpath,scale=-1,center=c1}] \mypath;
\path[homothety={store in=\thirdpath,scale=-2,center=c1,name=B}] \mypath;
% draw them
\draw[filled shape=green] \secondpath;
\draw[filled shape=green] \thirdpath;
% for each vertex of \thirdpath, add a label and draw a dashed line to
% corresponding vertex of \mypath
\foreach \num in {1,...,\nbpoints} {
\node[below] at (B-\num) {$B_\num$};
\draw[dashed line=green] (B-\num) -- (A-\num);
}

% second center: c2
\fill[dot=red] (-4,-1) coordinate (c2) circle(2pt) node[above]{$c_2$};
% store two homothetic transformations of \mypath
\path[homothety={store in=\secondpath,scale=2,center=c2,name=C}] \mypath;
\path[homothety={store in=\thirdpath,scale=.5,center=c2}] \mypath;
% draw them
\draw[filled shape=red] \secondpath;
\draw[filled shape=red] \thirdpath;
% for each vertex of \thirdpath, draw a dashed line to center and add a label
\foreach \num in {1,...,\nbpoints} {
\node[above] at (C-\num) {$C_\num$};
\draw[dashed line=red] (C-\num) -- (c2);
}
\end{tikzpicture}
\end{document}


Simple solution but with limitations

You can use calc library and scopes with scale and shift options to draw homothetic transformations. It is simple but your path must be defined only by numeric coordinates.

Result:

Code (commented):

\documentclass[margin=5mm]{standalone}
\usepackage{tikz}
\usetikzlibrary{calc}
\begin{document}
\begin{tikzpicture}
% some styles
\tikzset{
filled shape/.style={draw=black,line width=1pt,fill=#1,fill opacity=.4},
dot/.style={draw,line width=.4pt,fill=#1!50!gray},
homothety at/.style args={#1 scaled by #2}{shift={($(#1)!#2!(0,0)$)},scale=#2},
}
% path definition (numeric coordinates only!)
\def\mypath{(0,0) to[bend right] ++(2,2) -- ++(-1,1) to[bend left] ++(-2,-2) -- cycle}
% draw this path
\draw[filled shape=cyan] \mypath;
% center of homothetic transformation
\fill[dot=green] (-1,2) coordinate (c1) circle(2pt) node[above]{$c_1$};
% first transformation (scale=-1, center=c1)
\begin{scope}[homothety at=c1 scaled by -1]
\draw[filled shape=red] \mypath;
\end{scope}
% second transformation (scale=2, center=c1)
\begin{scope}[homothety at=c1 scaled by 2]
\draw[filled shape=red] \mypath;
\draw[dashed] (c1) -- (0,0);
\draw[dashed] (c1) -- (2,2);
\draw[dashed] (c1) -- (1,3);
\draw[dashed] (c1) -- (-1,1);
\end{scope}
\end{tikzpicture}
\end{document}

-

run with xelatex or latex->dvips->ps2pdf

\documentclass[pstricks,border=15pt]{standalone}
\begin{document}

\begin{pspicture}[showgrid](-5,-5)(5,5)
\pspolygon[linecolor=red!60,fillstyle=solid,fillcolor=red!40!white](-2,-3)(-1,-1)(1,-1)%
\psHomothetie(0,0){-1.5}{\pspolygon[linecolor=blue!60,fillstyle=solid,fillcolor=blue!40!white](-2,-3)(-1,-1)(1,-1)}
\psHomothetie(0,0){1.5}{\pspolygon[linecolor=green!60,fillstyle=solid,fillcolor=green!40!white,opacity=0.5](-2,-3)(-1,-1)(1,-1)}
\psset{linestyle=dashed,linewidth=0.5pt}
\psRelLine(0,0)(-2,-3){-1.75}{A'}\psRelLine(0,0)(-2,-3){1.7}{A}
\psRelLine(0,0)(-1,-1){-1.75}{B'}\psRelLine(0,0)(-1,-1){1.7}{B}
\psRelLine(0,0)(1,-1){-1.75}{C'}\psRelLine(0,0)(1,-1){1.7}{C}

\qdisk(0,0){2pt}
\end{pspicture}

\end{document}


you can use any object for this, not only polygons. Here an example for an image:

-

I now managed to do the following. Any suggestions for improvements?

\documentclass{article}

\usepackage{tikz}
\usetikzlibrary{calc}
\begin{document}

\newcommand {\defPoly}[3]
{
\pgfmathsetmacro{\m}{#2};%
\coordinate (Z) at #3;%
\draw (Z) circle (1pt);%
\path \foreach \coord [count=\ni] in {#1} {\coord coordinate (a\ni)};
\foreach \k [count=\ni] in {#1} {%
\global\let\nb\ni};

\draw (a1) \foreach \i in {2,...,\nb} {--(a\i)} --cycle; %
\foreach \i in {1,...,\nb} {\coordinate (b\i) at ($(Z) + \m*(a\i)-\m*(Z)$);}%

\draw (b1) \foreach \i in {2,...,\nb} {--(b\i)} -- cycle;%
\foreach \i in {1,...,\nb}{\draw[dashed] (Z) -- (b\i);\draw[dashed] (Z) -- (a\i);}%

}

\begin{tikzpicture}[]
\defPoly{(0,0),(2,2),(1,3),(-2,4)}{3}{(-2,2)};
\end{tikzpicture}
\end{document}


Output:

-

Just another solution with PSTricks.

## Still Version:

\documentclass[pstricks,border=12pt]{standalone}
\usepackage{pst-eucl}

\begin{document}

\begin{pspicture}[showgrid](-4,-3)(8,6)
% Setup the original polygon points
\pstGeonode[PosAngle={135,135,135,-45}]
(2,2){O}
(4,5){A}
(6,5){B}
(7,3){C}
% Setup the image points
\pstHomO[HomCoef=-1.1,PosAngle={315,315,135}]{O}{A,B,C}
% Draw auxiliary lines
\psset{nodesepA=-6,nodesepB=-1,linestyle=dashed,linecolor=gray}
\pstLineAB{O}{A}
\pstLineAB{O}{B}
\pstLineAB{O}{C}
% Draw the polygons
\psset{linestyle=solid,linejoin=2,linecolor=black,fillstyle=solid,opacity=0.25}
\pspolygon[fillcolor=red](A)(B)(C)
\pspolygon[fillcolor=blue](A')(B')(C')
\end{pspicture}

\end{document}


## Animated Version:

\documentclass[pstricks,border=12pt]{standalone}
\usepackage{pst-eucl,multido,fp}

\begin{document}

\multido{\n=0.7+-0.3}{7}{%
\begin{pspicture}[showgrid](-4,-3)(8,6)
% Setup the original polygon points
\pstGeonode[PosAngle={135,135,135,-45}]
(2,2){O}
(4,5){A}
(6,5){B}
(7,3){C}
% Setup the image points
\FPifgt\n0
\pstHomO[HomCoef=\n,PosAngle={135,135,-45}]{O}{A,B,C}
\else
\pstHomO[HomCoef=\n,PosAngle={315,315,135}]{O}{A,B,C}
\fi
% Draw auxiliary lines
\psset{nodesepA=-6,nodesepB=-1,linestyle=dashed,linecolor=gray}
\pstLineAB{O}{A}
\pstLineAB{O}{B}
\pstLineAB{O}{C}
% Draw the polygons
\psset{linestyle=solid,linejoin=2,linecolor=black,fillstyle=solid,opacity=0.25}
\pspolygon[fillcolor=red](A)(B)(C)
\pspolygon[fillcolor=blue](A')(B')(C')
\end{pspicture}}

\end{document}


## Animated version with an image:

\documentclass[pstricks,border=12pt]{standalone}
\usepackage{pst-eucl,multido,graphicx,fp}
\psset{PointName=none,PointSymbol=none}

\def\filename{../../../../../Images/ParisHilton}

\newsavebox\IBox
\savebox\IBox{\includegraphics[scale=0.5]{\filename}}
\psset{xunit=\dimexpr\wd\IBox/8,yunit=\dimexpr\ht\IBox/6}

\begin{document}

\multido{\n=0.80+-0.25}{8}{%
\begin{pspicture}[showgrid](-14,-9)(8,6)
% Setup the original polygon points
\pstGeonode
(-2,-1){O}
(8,6){A}
([nodesep=-\wd\IBox]A){B}
([nodesep=-\wd\IBox,offset=-\ht\IBox]A){C}
([offset=-\ht\IBox]A){D}
% Setup the image points
\pstHomO[HomCoef=\n]{O}{A,B,C,D}
% Place the images
\rput[tr](A){\usebox\IBox}
\FPifgt\n0\rput[tr](A'){\scalebox{\n}{\usebox\IBox}}\fi
\FPifeq\n0\relax\fi
\FPiflt\n0\rput[tr](C'){\scalebox{\n}{\usebox\IBox}}\fi
% Draw auxiliary lines
\psset{nodesepA=-6.5,nodesepB=-.25,linestyle=dashed,linecolor=red}
\pstLineAB{O}{A}
\pstLineAB{O}{B}
\pstLineAB{O}{C}
\pstLineAB{O}{D}
\end{pspicture}}

\end{document}

-
Hopefully the next built of PSTricks has provided us with a new feature in which the point labels are automatically placed on the angle bisector of the angle in question. –  The Last Error Sep 16 '12 at 16:32