Take the 2-minute tour ×
TeX - LaTeX Stack Exchange is a question and answer site for users of TeX, LaTeX, ConTeXt, and related typesetting systems. It's 100% free, no registration required.

I would like to create some new shape in order to use it with tiKz. The problem I'm front facing is how to access edged of the newly created shapes.

So far I got this :

\documentclass[paper=a4,11pt,parskip=half,twoside]{scrartcl}
\usepackage{amsmath}
\usepackage{amsfonts}
\usepackage[utf8]{inputenc}
\usepackage[T1]{fontenc}
\usepackage[french]{babel}
\usepackage[pdftex]{graphicx}

\usepackage{tikz}
\usepackage{circuitikz}
\usepackage{pgfplots}

\def\convEl{%
    ++(-.5,-.5) -- ++(1,0) -- ++(0,1) -- ++(-1,0) -- cycle
}

\def\convEm{%
    ++(0,0) circle (.5)
}

\def\convMe{%
    ++(-.5,-.5) -- ++(.5,1) -- ++(.5,-1) -- cycle
}

\def\accEn{%
    ++(-.5,-.5) -- ++(.5,0) -- ++(0,1) -- ++(-.5,0) -- cycle ++(0,-1) -- ++(.5,1)
}

\begin{document}

\begin{tikzpicture}
    \filldraw[draw=red,ultra thick,fill=orange] (0,0) \convEl node (a) {};
    \filldraw[draw=red,ultra thick,fill=orange] (2,0) \convEm node (b) {};
    \filldraw[draw=red,ultra thick,fill=orange] (4,0) \convMe;
    \filldraw[draw=red,ultra thick,fill=orange] (6,0) \accEn;
\end{tikzpicture}

\end{document}

Well maybe I should precise some more in comparison to the code provided. I want to access specific positions of my shapes, like bottom center and +30°/-30° on each side to connect arrows. Here is a little scheme of the behaviour expected. This is why I need to create / access some more anchors. If i draw a simple rectangle, I can do it, but with new/special shapes like the one I need...

Arrows connection

share|improve this question

3 Answers 3

up vote 11 down vote accepted

Using Spike's approach is for sure a possibility, but the shape to be defined is quite simple, so I think there's a simplest way. Credit should go to Jake's answer How to have a cross out rectangle in tikz?, because here I just adapted things.

\documentclass{article}
\usepackage{tikz}
\usetikzlibrary{shapes.geometric}

\tikzset{
        orange square/.style={draw=red,ultra thick, fill=orange,%
        minimum width=1cm, minimum height=1cm},%
        orange circle/.style={circle,draw=red,ultra thick, fill=orange,minimum width=1cm},%
        orange triangle/.style={regular polygon, regular polygon sides=3,%
        draw=red,ultra thick, fill=orange,minimum height=1cm},%
        orange rectangle/.style={rectangle,draw=red,ultra thick,%
        fill=orange,minimum height=1cm,minimum width=0.5cm,append after command={                       
            (\tikzlastnode.north east) edge[draw=red,ultra thick,shorten >=1.75\pgflinewidth,
                shorten <=1.75\pgflinewidth,](\tikzlastnode.south west)
            }
        },%
}

\begin{document}
\begin{tikzpicture}[scale=1.75,transform shape]
\node[orange square] (a) at (0,0){};
\node[orange circle] (b) at (2,0){};
\node[orange triangle] (c) at (4,0){};
\node[orange rectangle] (d) at (6,0){};
\draw[->,>=stealth] (a.south) -- (b.west) (b.north) -- (c.north)-- (d.center);
\end{tikzpicture}
\end{document}

Result:

enter image description here


The edit of the question was very useful to better understand the request. In this case perhaps it is better to define a new shape, but that's Spike's domain: I provide you an alternative. Ok, it could be an alternative if one is used to the calc library.

The basic hint is that regular polygons define also corner anchors so, by taking them as reference, it is possible to access every position without defining a new shape.

The revised example:

\documentclass{article}
\usepackage{tikz}
\usetikzlibrary{shapes.geometric,calc}

\tikzset{
        orange square/.style={regular polygon, regular polygon sides=4,%
        draw=red,ultra thick, fill=orange,minimum width=1.5cm},%
        orange triangle/.style={regular polygon, regular polygon sides=3,%
        draw=red,ultra thick, fill=orange,minimum height=1.5cm},%
        }

\begin{document}

\begin{tikzpicture}[scale=1.75,transform shape]
\node[orange square,] (e) at (0,-2){};
\node[orange triangle] (f) at (4,-2.165){};

% Display the anchors
\foreach \anchor/\placement in {corner 1/above, corner 2/above, corner 3/below, corner 4/below}
\draw[shift=(e.\anchor)] plot[mark=x] coordinates{(0,0)}node[\placement] {\tiny\texttt{(e.\anchor)}};

\foreach \anchor/\placement in {corner 1/above, corner 2/below, corner 3/below}
\draw[shift=(f.\anchor)] plot[mark=x] coordinates{(0,0)}node[\placement] {\tiny\texttt{(f.\anchor)}};

% Drawing the arrows    
\draw[-latex] ($(e.corner 3)!0.5!(e.corner 4)-(0,1)$)--($(e.corner 3)!0.5!(e.corner 4)$);
\draw[-latex] ($(e.corner 1)!0.2!(e.corner 4)$)--($(f.corner 1)!0.25!(f.corner 2)$);
\draw[-latex] ($(e.corner 1)!0.5!(e.corner 4)$)--($(f.corner 1)!0.525!(f.corner 2)$);
\draw[-latex] ($(e.corner 1)!0.8!(e.corner 4)$)--($(f.corner 1)!0.8!(f.corner 2)$);
\end{tikzpicture}
\end{document}

Result:

enter image description here

share|improve this answer
    
I think I can really go further with your explanations. –  s__C Oct 6 '12 at 9:46

Creating new shapes is not very easy. It requires an accurate reading of the tikz manual (section 75.5) and some skills in TeX programming. By the way, if I have been able to do that, everyone can. If you want to create real shapes you can refer to the above mentioned manual and to other previous questions (like How to define mechanical constraint in TikZ).

The first three examples you give can be achieved just using styles. The third one maybe needs a definition, but it is not so hard given that it is quite similar to a rectangle:

\documentclass{scrartcl}
\usepackage{tikz}
\usetikzlibrary{shapes.geometric} %needed for the triangle

\makeatletter    
\pgfdeclareshape{myrectangle}{% taken and modified from page 631 of the manual
  \inheritsavedanchors[from=rectangle] %  this is nearly a rectangle
  \inheritanchorborder[from=rectangle]
  \inheritanchor[from=rectangle]{center}
  \inheritanchor[from=rectangle]{north}
  \inheritanchor[from=rectangle]{south}
  \inheritanchor[from=rectangle]{west}
  \inheritanchor[from=rectangle]{east}
  %  ... and possibly more
  \backgroundpath{%  this is new
    %  store lower right in xa/ya and upper right in xb/yb
    \southwest \pgf@xa=\pgf@x \pgf@ya=\pgf@y
    \northeast \pgf@xb=\pgf@x \pgf@yb=\pgf@y
    %  construct main path
    \pgfpathmoveto{\pgfpoint{\pgf@xa}{\pgf@ya}}
    \pgfpathlineto{\pgfpoint{\pgf@xa}{\pgf@yb}}
    \pgfpathlineto{\pgfpoint{\pgf@xb}{\pgf@yb}}
    \pgfpathlineto{\pgfpoint{\pgf@xb}{\pgf@ya}}
    \pgfpathlineto{\pgfpoint{\pgf@xa}{\pgf@ya}}
    \pgfpathclose
    %  add diagonal
    \pgfpathmoveto{\pgfpoint{\pgf@xa}{\pgf@ya}}
    \pgfpathlineto{\pgfpoint{\pgf@xb}{\pgf@yb}}
 }
}
\pgfdeclareshape{mytriangle}{%
  \inheritsavedanchors[from=circle]
  \inheritanchor[from=circle]{center}
  \anchor{north}{\centerpoint\advance\pgf@y by\radius}
  \anchor{south}{\centerpoint\advance\pgf@y by-\radius}
  %etc...
  \anchor{west}{%
    \centerpoint
    \pgf@xa=\radius
    % y = -1.5*r*tan(alpha)
    \advance\pgf@x by-1\pgf@xa
    \advance\pgf@y by-1.5\pgf@xa
  }
  \anchor{east}{%
    \centerpoint
    \pgf@xa=\radius
    % y = 1.5*r*tan(alpha)
    \advance\pgf@x by1\pgf@xa
    \advance\pgf@y by-1.5\pgf@xa
  }
  \anchor{south west}{%
    \centerpoint
    \pgf@xa=\radius
    \advance\pgf@x by-\pgf@xa
    \advance\pgf@y by-\pgf@xa
  }
  \anchor{south east}{%
    \centerpoint
    \pgf@xa=\radius
    \advance\pgf@x by\pgf@xa
    \advance\pgf@y by-\pgf@xa
  }
  \backgroundpath{%
      \pgf@x=\radius
      \pgfutil@tempdima=\pgf@x%
      \pgf@xb=-\pgf@x%
      \pgf@yb=-\pgf@x%
      \pgf@xc= \pgf@x%
      \pgf@yc=-\pgf@x%
      \centerpoint
      \advance\pgf@xb by\pgf@x
      \advance\pgf@yb by\pgf@y
      \advance\pgf@xc by\pgf@x
      \advance\pgf@yc by\pgf@y
      \pgf@xa=\pgf@x
      \pgf@ya=\pgf@y
      \advance\pgf@ya by\radius%
      \pgfpathmoveto{\pgfpoint{\pgf@xa}{\pgf@ya}}%
      \pgfpathlineto{\pgfpoint{\pgf@xb}{\pgf@yb}}%
      \pgfpathlineto{\pgfpoint{\pgf@xc}{\pgf@yc}}%
      \pgfpathclose%
      \advance\pgf@ya by-\radius%
  }%
}
\makeatother
% now the styles
\tikzset{orangesquare/.style={draw=red,ultra thick, fill=orange,minimum width=1cm, minimum height=1cm},%
         orangecircle/.style={circle,draw=red,ultra thick, fill=orange,minimum width=1cm},%
         orangetriangle/.style={regular polygon, regular polygon sides=3,draw=red,ultra thick, fill=orange,minimum height=1cm},%
         orangetriangle/.style={mytriangle,draw=red,ultra thick, fill=orange,minimum height=1cm}}

\begin{document}
\begin{tikzpicture}
\node[orangesquare] (a) at (0,0){};
\node[orangecircle] (b) at (2,0){};
\node[orangetriangle] (c) at (4,0){};
\node[orangerectangle] (d) at (6,0){};
\draw[->,>=stealth] (a.south) -- (b.west) (b.north) -- (c.north) -- (d.center);
\end{tikzpicture}
\end{document}

enter image description here

I've created the triangle using the circle anchors (center and radius). As you can see there is a difference between it and the other shapes: the minimum width does not take into account of the line width. It is possible to fix the anchor positions shifting them to the external part of the shape, but it is necessary to adjust a bit the minimum dimension anyway. Unfortunately, I don't know how to fix this. Maybe I'll post it as a question.

share|improve this answer
    
Thanks for your answer. With my edit, it seems more accurate to accept Fiandrino's answer, but you get the credit for the shapes. –  s__C Oct 6 '12 at 9:47
    
Do you know how to define the triangle in order to be bottom aligned like in the picture I did in the question ? –  s__C Oct 6 '12 at 10:08
    
@s__C Edited the question as requested –  Spike Oct 7 '12 at 7:13

I bring two more ways to solve the proposed problem.

  • One is a standard feature of tikz and
  • the other is an automated way to create addressable nodes along the path that describes the picture.

And I also have a proposal to solve the bottom alignment of the triangle, as you asked in the comments.

Here you can see the result:

Access positions

And here you can see the code:

\documentclass [tikz] {standalone}

\usetikzlibrary{decorations.markings}
\usetikzlibrary{shapes.geometric}

\newcounter{mynodes}

\tikzset{
    my anchors/.style = {
        draw = red
        , ultra thick
        , fill = orange
        , postaction={
            /utils/exec=\setcounter{mynodes}{0}
            , decorate
            , decoration={
                markings,
                mark=between positions 0 and 1 step 3mm with {
                    \coordinate (#1 \themynodes);
                    \node at (#1 \themynodes) {\tiny \themynodes}; \stepcounter{mynodes}
                }
            }
        }
    }
    , degrees/.style = {
        draw = red
        , minimum size = 2cm
        , ultra thick
        , fill = orange
        , anchor = south west
    }
}

\newlength{\shifiting}
\setlength{\shifiting}{3cm}

\begin{document}
    \begin{tikzpicture}[]
        \draw [my anchors = circle 1] (1,1) circle (1);
        \draw [my anchors = square 1, xshift = \shifiting] (0,0) rectangle (2, 2);
        \draw [my anchors = triangle 1, xshift = 2\shifiting] (0,0) -- (1, 2) -- (2,0) -- cycle;
        \draw [my anchors = crossed rectangle 1, xshift = 3\shifiting] (1,2) -- (0, 2) -- (0,0) -- (1,0) -- cycle -- (0,0);

        \draw (circle 1 12) -- (square 1 14) -- (triangle 1 13) -- (crossed rectangle 1 24);

        \node [anchor = south west, minimum size = 2cm] (ref 1) at (0 , 1\shifiting) {};
        \node [circle, degrees, anchor = center] (circle 2) at (ref 1) {};

        \node [degrees] (square 2) at (\shifiting, \shifiting) {};

        \node [anchor = south west, minimum size = 2cm] (ref 2) at (2\shifiting , \shifiting) {};
        \node [degrees, isosceles triangle, rotate = 90, anchor = left corner, isosceles triangle stretches] (triangle 2) at (ref 2.south west) {};
        \node [degrees, minimum width = 1cm] (crossed rectangle 2) at (3\shifiting, \shifiting) {};
        \path [draw = red, ultra thick] (crossed rectangle 2.north east) -- (crossed rectangle 2.south west);

        \draw (circle 2.230) -- (square 2.30) -- (triangle 2.-110) -- (crossed rectangle 2.center);

    \end{tikzpicture}
\end{document}

Hope this helps.


Edit

Well, from questioning about the alignment of nodes I leave here two more proposals, which somehow leads to the question of symmetry into account.

The first uses divisions at edges of each polygon, but a special treatment had to be given to circle. Here you can see the result:

Divided edges

And the code:

\documentclass [tikz] {standalone}

\usetikzlibrary{decorations.markings}
\usetikzlibrary{shapes.geometric}
\usetikzlibrary{calc}

\newcounter{mynodes}

% node, begin anchor, end anchor, name
\newcommand{\makepoints}[4]{
    \foreach \k in {1, ..., \points}
    {
        \pgfmathsetmacro{\dist}{\k * (1 / (\points + 1))}
        \coordinate (#1 #4 \k) at ($(#1.#2)!\dist!(#1.#3)$);
    }
}

% node, begin degree, end degree, name
\newcommand{\makepointsbydegrees}[4]{
    \foreach \k in {1, ..., \points}
    {
        \pgfmathsetmacro{\step}{(abs(#3) - abs(#2)) / (\points + 1)}
        \pgfmathsetmacro{\step}{ifthenelse(#2 < 0, -\step,)}
        \pgfmathsetmacro{\degree}{#2 + \k * \step}

        \coordinate (#1 #4 \k) at (#1.\degree);
    }
}

\tikzset{
    base/.style = {
        draw = red
        , line join = round
        , line cap = round
        , minimum size = 2cm
        , ultra thick
        , fill = orange
    }
    , ref/.style = {
        , minimum size = 2cm
        , anchor = south west
    }
}

\newlength{\shifiting}
\setlength{\shifiting}{3cm}

\begin{document}
    \begin{tikzpicture}[]
        \pgfmathtruncatemacro{\points}{3}

        % circle
        \node [ref] (ref 1) at (0 , 1\shifiting) {};
        \node [base, circle, anchor = center] (circle) at (ref 1) {};

        \makepointsbydegrees{circle}{-270}{-450}{right}

        % square
        \node [ref] (ref 2) at (\shifiting, \shifiting) {};
        \node [base] (square) at (ref 2) {};

        \makepoints{square}{north east}{south east}{right}
        \makepoints{square}{north west}{south west}{left}


        % triangle
        \node [ref] (ref 3) at (2\shifiting , \shifiting) {};
        \node [base, isosceles triangle, rotate = 90, anchor = left corner, isosceles triangle stretches] (triangle) at (ref 3.south west) {};

        \makepoints{triangle}{east}{left corner}{left}
        \makepoints{triangle}{east}{right corner}{right}


        % crossed retangle
        \node [ref, minimum width = 1cm] (ref 4) at (3\shifiting, \shifiting) {};
        \node [base, minimum width = 1cm] (crossed rectangle) at (ref 4) {};
        \path [base, shorten >= 2pt, shorten <= 2pt] (crossed rectangle.north east) -- (crossed rectangle.south west);

        \makepoints{crossed rectangle}{north west}{south west}{left}


        % lines

        \foreach \i in {1, ..., \points}
        {
            \draw [->] (circle right \i) -- (square left \i);
            \draw [->] (square right \i) -- (triangle left \i);
            \draw [->] (triangle right \i) -- (crossed rectangle left \i);
        }

    \end{tikzpicture}
\end{document}

The second brings a totally different paradigm, using more of the power offered by Tikz, like through, matrix, fit and intersections. In the next picture you can see the result and a little bit of the construction lines.

external structures

And the code:

\documentclass [tikz] {standalone}

\usetikzlibrary{fit}
\usetikzlibrary{intersections}
\usetikzlibrary{calc}
\usetikzlibrary{matrix}
\usetikzlibrary{through}

% node, begin anchor, end anchor, name
\newcommand{\makepoints}[4]{
    \foreach \k in {1, ..., \points}
    {
        \pgfmathsetmacro{\dist}{\k * (1 / (\points + 1))}
        \coordinate (#1 #4 \k) at ($(#1.#2)!\dist!(#1.#3)$);
    }
}

% first path, second path, counter
\newcommand{\intersectpoints}[3]{
    \path [name intersections = {of = #1 and #2, sort by = #2, name = #3, total = \t}] 
        \foreach \s in {1, ..., \t} {
            node [fill, circle, inner sep = 1.5pt] at (#3-\s) {}
        };
}

\tikzset{
    base/.style = {
        draw = red
        , line join = round
        , minimum size = 2cm
        , ultra thick
        , fill = orange
        , name path = #1
    }
    , ref/.style = {
        , minimum size = 2cm
        , anchor = south west
    }
    , cr/.style = {
        , minimum width = 1cm
        , minimum height = 2cm
    }
    , conexion/.style = {
        , ->
        , thick
        , draw = blue
    }
}

\begin{document}
    \begin{tikzpicture}[]

        % number of reference lines
        \pgfmathtruncatemacro{\points}{4}

        \matrix (m) [matrix of nodes, nodes in empty cells, nodes = {ref}]
        {
            & & & & & & \\
        };

        \node [base = circle] at (m-1-1) [circle through={(m-1-1.east)}] {};
        \draw [base = square] (m-1-3.south west) rectangle (m-1-3.north east);
        \draw [base = triangle] (m-1-5.south west) -- (m-1-5.south east) -- (m-1-5.north) -- cycle;

        \node [draw, cr] (cr) at (m-1-7){};
        \draw [base = crossed rectangle] (cr.north east) -- (cr.north west) -- (cr.south west) -- (cr.south east) -- cycle -- (cr.south west);


        % reference rectangle fitting all figures
        \node [draw, dotted, inner sep = 0pt, fit = (m-1-1) (m-1-7)] (outline) {};
        \makepoints{outline}{north west}{south west}{left}
        \makepoints{outline}{north east}{south east}{right}

        % reference lines through figures
        \draw [dotted, name path = path 1] (outline left 1) -- (outline right 1);
        \draw [dotted, name path = path 2] (outline left 2) -- (outline right 2);
        \draw [dotted, name path = path 3] (outline left 3) -- (outline right 3);
        \draw [dotted, name path = path 4] (outline left 4) -- (outline right 4);

        % circle points
        \intersectpoints{circle}{path 1}{c 1}
        \intersectpoints{circle}{path 2}{c 2}
        \intersectpoints{circle}{path 3}{c 3}

        % square points
        \intersectpoints{square}{path 1}{r 1}
        \intersectpoints{square}{path 2}{r 2}
        \intersectpoints{square}{path 3}{r 3}

        % triangle points
        \intersectpoints{triangle}{path 1}{t 1}
        \intersectpoints{triangle}{path 2}{t 2}
        \intersectpoints{triangle}{path 3}{t 3}

        % crossed rectangle
        \intersectpoints{crossed rectangle}{path 1}{cr 1}
        \intersectpoints{crossed rectangle}{path 2}{cr 2}
        \intersectpoints{crossed rectangle}{path 3}{cr 3}

        % lines between circle and square
        \draw [conexion] (c 1-2) -- (r 1-1);
        \draw [conexion] (c 2-2) -- (r 2-1);
        \draw [conexion] (c 3-2) -- (r 3-1);

        % lines between square and triangle
        \draw [conexion] (r 1-2) -- (t 1-1);
        \draw [conexion] (r 2-2) -- (t 2-1);
        \draw [conexion] (r 3-2) -- (t 3-1);

        % lines between triangle and crossed rectangle
        \draw [conexion] (t 1-2) -- (cr 1-2);
        \draw [conexion] (t 2-2) -- (cr 2-2);
        \draw [conexion] (t 3-2) -- (cr 3-1);

    \end{tikzpicture}
\end{document}

Hope you enjoyed.

share|improve this answer
    
in this way the nodes are not vertically aligned, so you can't achieve the @s__C request without fine hand tuning the node positioning. Am I right? –  Spike Oct 7 '12 at 8:08
    
Could you insert the complete example rather than the code snippet? This would help people to try immediately your example. :) –  Claudio Fiandrino Oct 7 '12 at 13:20
    
oops! sorry about that! updated! =) –  tecepe Oct 7 '12 at 13:26
    
@Spike: There is a problem of accuracy in positioning, but it is a very general proposal. I updated my answer with more specific codes. –  tecepe Oct 8 '12 at 3:55
    
This is great ! Thx –  s__C Oct 8 '12 at 6:56

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.