15

When calculating the intersection point(s) between a line and another double-line path, TikZ normally returns the intersection at the middle of the double-line path. The question here is how to get the intersection with the outer line of the path. I believe, we can shift the point by a value .5\pgflinewidth + .5\pgfinnerlinewidth, but I'm using this inside a macro which should check first if the path is double or not, then, it can do the correction. The code currently is like this:

\documentclass[tikz,border=1mm]{standalone}
\usetikzlibrary{intersections}
\begin{document}

\begin{tikzpicture}
\node (rect) [name path=rect,draw,double,ultra thick,double distance=3pt, rounded corners,minimum size=1cm]{};
\draw[name path=line] (rect.center)--(.7,.7);
\path[name intersections={of= rect and line}];
\node at (intersection-1) [circle,fill=blue,inner sep=.5pt]{};
\end{tikzpicture}

\end{document}

enter image description here

I appreciate your advice.

Comment on @Augustin's answer:

This should be a comment, but posting the picture needs editing here. The answer of Augustin is only valid for the case of the line slope being 45 degrees, which is rarely the case. Try, for example,

...
\draw[name path=line,draw] (rect.center)--(.7,.1);
..

you get the following result:

enter image description here

I appreciate the trial, but I need a general solution. More importantly, I mentioned in my question that I can shift the point. What I need to accomplish is how to check if the path is double and how to get the keys for its innerlinewidth, total linewidth, ... etc (all the information you have is the path itself), to be able to do the correct shifting.

  • You can check if \pgfinnerlinewidth>0 or not. – user11232 Apr 11 '15 at 0:11
  • @HarishKumar - The key \pgfinnerlinewidth is always >0 if you have a single double path in the whole tikzpicture environment. So, how to check a specific path, rect for example, and you have many other single/double paths? – AboAmmar Apr 11 '15 at 0:19
  • I mean the path has been created outside of the macro, and all you have about the path is its name (rect), so how can we extract the properties and keysvalues of a path only by its name. It is actually passed to the macro (as an argument) only by its name. – AboAmmar Apr 11 '15 at 0:28
  • @AboAmmar path actions (e.g., drawing, filling) and properties (e.g., line width, color) are independent of the path specification (i.e., its shape). The name path key only saves the path specification. Currently there is no way to save the actions and properties of a path, and they are essentially 'forgotten' once the path is used. – Mark Wibrow Apr 11 '15 at 8:20
  • I would suggest cheating a bit, but I do not know if it will work: first find the intersection with the single path, then "double-line-draw" (with another color) the "path" consisting of two points, I--I, where I would be the previously intersection. – Franck Pastor Apr 11 '15 at 14:38
8

You can use the calc TikZ package to do the job:

\documentclass[tikz,border=1mm]{standalone}
\usetikzlibrary{intersections,calc}
\begin{document}

\begin{tikzpicture}
\def \borderSep {3pt} % Define the border separation as a constant
\node (rect) [name path=rect,draw,double,ultra thick,double distance=\borderSep, rounded   corners,minimum size=1cm]{};
\draw[name path=line,draw] (rect.center)--(.7,.7);
\path[name intersections = {of=rect and line, by={a}}];
% Offset the nodes by sqrt(2) * separation
\node at ($(a) + 1/1.41*(\borderSep,\borderSep)$) [circle,fill=blue,inner sep=.5pt]{};
\node at ($(a) - 1/1.41*(\borderSep,\borderSep)$) [circle,fill=blue,inner sep=.5pt]{};
\end{tikzpicture}

\end{document}

This is what you get: enter image description here

Edit: More general solution:

\documentclass[tikz,border=1mm]{standalone}
\usetikzlibrary{intersections,calc}
\begin{document}

\begin{tikzpicture}
% If the rect has single border, set borderSep and borderThickness to 0pt
\def \borderSep {3pt}
\def \borderThickness {1.5pt}
\node (rect) [name path=rect,draw,double,ultra thick,double distance=\borderSep,rounded corners,minimum size=1cm]{};
\draw[name path=line,draw] (rect.center)--(.7,.1);

% Construct invisible rectangles at the positions of the borders
\node (rect) [name path=rectIn, rounded corners=6pt, minimum size=1cm+\borderSep+\borderThickness]{};
\node (rect) [name path=rectOut, rounded corners=2pt, minimum size=1cm-\borderSep-\borderThickness]{};

\path[name intersections = {of=rectIn and line, by={intIn}}];
\path[name intersections = {of=rectOut and line, by={intOut}}];
\node at (intIn) [circle,fill=blue,inner sep=.5pt]{};
\node at (intOut) [circle,fill=blue,inner sep=.5pt]{};
\end{tikzpicture}

\end{document}

Now this works even in the general case. Note that if you want more fine-grained control you need to edit (e.g. using a global variable) the radii of the rectIn's and rectOut's rounded corners. enter image description here

  • Thank you for trying, but see my edit. – AboAmmar Apr 10 '15 at 21:49
  • I added more general solution, see my edit. – Augustin Apr 11 '15 at 9:21
  • This won't work if the double line does not belong to a node though. – percusse Apr 11 '15 at 13:06
  • Also, since you are already building the inner and outer lines as invisible nodes, wouldn't it be more straightforward to build them as visible nodes and forget about the doubled line node? – Guilherme Zanotelli Oct 18 '16 at 5:18
2

Here is a mathematical way that uses \dimexpr where needed to be unit-independed (works with pt, or cm or whatever).

It works only for line (added with \myline command but it can take parameters as a real tikz line). The line can start from any point and stop to any other, but had to intersects with double path.

Also the distance of double path parts has to be defined in \DoubleDist variable. The code I suppose can be more general and work for ultra thick (but haven't yet include such parameter and I don't know if can be added without one more definition of new parameter).

Finally, the shape (circle) on the intersections is better to be chosen from the user but I was tired to do this too. (Anyone who can understand the code can do it himself I suppose).

Code:

\documentclass[tikz,border=1mm]{standalone}
\usetikzlibrary{intersections}
\usetikzlibrary{calc}
\begin{document}

\def\DoubleDist{4.1 pt}


%\Usage \myline(x1,y1)(x2,y2)[parameters]=\draw[parameters] (x1,y1)--(x2,y2); +keep needed numbers
\makeatletter
\def\myline{\@ifnextchar({\readFirstOPoint}{\node at (0,0){Error in line 1};}}
\def\readFirstOPoint(#1,#2){
\gdef\lineXStart{#1}
\gdef\lineYStart{#2}
\@ifnextchar(
{\readSecondPoint}
{\node at (0,0){Error in line 2};}
}
\def\readSecondPoint(#1,#2){
\gdef\lineXStop{#1}
\gdef\lineYStop{#2}
\readParametersAndDraw
}
\def\readParametersAndDraw
{\@ifnextchar[{\Storeparam}{\gdef\LineParam{\empty}\ExecuteLine}}
\def\Storeparam[#1]
{
\gdef\LineParam{[#1]}
\ExecuteLine
}
\def\ExecuteLine
{
\draw\LineParam (\lineXStart,\lineYStart)--(\lineXStop,\lineYStop);
}
\makeatother


% Will be used to shift the point
\newlength{\xsh}
\newlength{\ysh}

% Finding double path intersections. Usage \FindIndersections(path)
\makeatletter
\def\FindIndersections{
\@ifnextchar({\ReadIndersection}{\node at (0,0){Error in readind indersection}}
}
\def\ReadIndersection(#1){
\pgfmathsetmacro\XShiftFactor{(\lineXStop-\lineXStart)/sqrt((\lineXStart-\lineXStop)^2+(\lineYStart-\lineYStop)^2)}
\pgfmathsetmacro\YShiftFactor{(\lineYStop-\lineYStart)/sqrt((\lineXStart-\lineXStop)^2+(\lineYStart-\lineYStop)^2)}
\setlength{\xsh}{\dimexpr\XShiftFactor\dimexpr\dimexpr\DoubleDist/2\relax+\pgflinewidth\relax\relax}
\setlength{\ysh}{\dimexpr\YShiftFactor\dimexpr\dimexpr\DoubleDist/2\relax+\pgflinewidth\relax\relax}
\draw[fill=blue] ($(#1)-(\the\xsh ,\the\ysh)$) circle (1pt);
\draw[fill=blue] ($(#1)+(\the\xsh, \the\ysh)$) circle (1pt);
}
\makeatother

\begin{tikzpicture}
\node (rect) [name path=rect,draw,double,double distance=\DoubleDist, rounded corners,minimum size=30 pt]{};
\myline(0.2,0)(0.8,0.3)[brown,name path=line]
\path[name intersections={of= rect and line}];
\FindIndersections(intersection-1)
\end{tikzpicture}

\end{document}

Output:

enter image description here

With some complicated shapes as a cloud the intersection does not find the real middle and so my way fails too:

code:

\begin{tikzpicture}
\node (rect) [name path=rect,draw,draw, cloud,,double,double distance=\DoubleDist,minimum size=1.3 cm]{};
\myline(0.2,0)(-0.7,-0.4)[brown,name path=line]
\path[name intersections={of= rect and line}];
\draw[fill=red] (intersection-1) circle (1pt);
\FindIndersections(intersection-1)
\end{tikzpicture} 

(with tikzlibrary shapes).

Result:

enter image description here

2
\documentclass[tikz,border=1mm]{standalone}
\usetikzlibrary{intersections,fit}
\begin{document}

\begin{tikzpicture}
\node (rect) [name path=rect,draw,double,ultra thick,double distance=3pt, rounded corners,minimum size=1cm]{};
\draw[name path=line] (rect.center)--(.7,.7);
\path[name intersections={of= rect and line}];
\node at (intersection-1) [circle,fill=blue,inner sep=.5pt]{};
\end{tikzpicture}

\begin{tikzpicture}
\node (inner-rect) [name path=inner-rect,draw,ultra thick,
minimum size=1cm-4.5pt,inner sep=0pt,rounded corners=1.5pt]{};
\node (outer-rect) [name path=outer-rect,draw,ultra thick,
minimum size=1cm+4.5pt,inner sep=0pt,rounded corners=4.5pt]{};
\foreach \X [count=\Y] in {45,90,210,-45}
{\draw[name path=line-\Y] (inner-rect.center)--(\X:0.8);
\path[name intersections={of=inner-rect and line-\Y}]
node at (intersection-1) [circle,fill=blue,inner sep=.5pt]{};
\path[name intersections={of=outer-rect and line-\Y}]
node at (intersection-1) [circle,fill=red,inner sep=.5pt]{};}
\end{tikzpicture}
\end{document}

enter image description here

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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