1

I have a half rectangle and a circle that may intersect with each other. The circle is first at a location far above the rectangle and it moves down till it intersects with the rectangle and even passes through. I'm interested in finding the path that is created from the intersection between the two paths. So far thanks to Heiko Oberiek I know how to produce the new path for a special case. I want to be able to use conditional statements to figure out if the two shapes are intersecting and if they are where is the location of the intersection and finally produce the new path from subtracting the two shapes. Here is the code that I have for creating the two shapes:

\documentclass{standalone}
\usepackage[T1]{fontenc}
\usepackage{tikz}
\usepackage{graphicx}
\usetikzlibrary{intersections}  
\begin{document}
\begin{tikzpicture}
\pgfmathsetmacro\minX{2}
\pgfmathsetmacro\maxX{10}
\pgfmathsetmacro\minY{4}
\pgfmathsetmacro\maxY{10}
\pgfmathsetmacro\CX{11}
\pgfmathsetmacro\CY{12}
\pgfmathsetmacro\CR{2}
\pgfmathsetmacro\Roundness{0.2}
\begin{scope} [local bounding box=BoxWest]
\def\pathone{(.5*\maxX + .5*\minX,\maxY) 
    -- (-\Roundness + \maxX,\maxY)
    arc (90:0:\Roundness)
 -- (\maxX,\minY +\Roundness)
    arc (360:270:\Roundness)
    -- (.5*\maxX+ .5*\minX,\minY )}
    \path [name path=pathone, draw=green] \pathone;         
    \path [name path=pathtwo, draw=blue](\CX,\CY)
    circle (\CR);
\end{scope}
\end{tikzpicture}
\end{document}

this code produces: enter image description here

changing the \CY from 12 to 10 produces: enter image description here

and so on. This is the code that I have which only works when the circle has intersections with half-rectangle at the vertical line (Subtracting two TikZ paths at their intersection):

\begin{tikzpicture}[x=10pt, y=10pt]
\pgfmathsetmacro\minX{2}
\pgfmathsetmacro\maxX{10}
\pgfmathsetmacro\minY{4}
\pgfmathsetmacro\maxY{10}
\pgfmathsetmacro\CX{11}
\pgfmathsetmacro\CY{7}
\pgfmathsetmacro\CR{3}
\pgfmathsetmacro\Roundness{0.2}

\pgfmathsetmacro\OneWestX{.5*\maxX + .5*\minX}
\pgfmathsetmacro\OneEastX{\maxX}
\pgfmathsetmacro\OneNorthY{\maxY}
\pgfmathsetmacro\OneSouthY{\minY}

\pgfmathsetmacro\DiffX{\CX-\OneEastX}
\pgfmathsetmacro\DiffY{sqrt(\CR * \CR - \DiffX * \DiffX)}
\pgfmathsetmacro\DiffAngle{acos(\DiffX/\CR)}

\def\paththree{
  (\OneWestX, \OneNorthY)
  -- (\OneEastX, \OneNorthY)
  -- (\OneEastX, \CY + \DiffY) % North intersection point
  arc (180 - \DiffAngle:180 + \DiffAngle: \CR)
  -- (\OneEastX, \OneSouthY)
  -- (\OneWestX, \OneSouthY)}
\draw \paththree;
\end{tikzpicture}

enter image description here

can anyone help me generalize this solution for any location of the circle with respect to the half-rectangle and any radius of it?

1 Answer 1

1

Here is a proposal.

\documentclass{article}
\usepackage{tikz,pgfplots}
\pgfplotsset{compat=1.15}
\usetikzlibrary{intersections,fillbetween} 

\begin{document}
\begin{tikzpicture}
\pgfmathsetmacro\minX{2}
\pgfmathsetmacro\maxX{10}
\pgfmathsetmacro\minY{4}
\pgfmathsetmacro\maxY{10}
\pgfmathsetmacro\CX{11}
\pgfmathsetmacro\CY{12}
\pgfmathsetmacro\CR{2}
\pgfmathsetmacro\Roundness{0.2}
\begin{scope} [local bounding box=BoxWest]
\def\pathone{(.5*\maxX + .5*\minX,\maxY) 
    -- (-\Roundness + \maxX,\maxY)
    arc (90:0:\Roundness)
 -- (\maxX,\minY +\Roundness)
    arc (360:270:\Roundness)
    -- (.5*\maxX+ .5*\minX,\minY )}
    \path [name path global=pathone, draw=green] \pathone;         
    \path [name path global=pathtwo, draw=blue](\CX,\CY)
    circle (\CR);
  \path [name intersections={of=pathone and pathtwo,total=\tot}]
  \pgfextra{\pgfmathsetmacro{\NonTriv}{ifthenelse(\tot>1,1,0)}% check if there 
  %are at least two intersections
  \xdef\XNonTriv{\NonTriv}% export the result
  };
\end{scope}
  \ifnum\XNonTriv=1
    \draw[red,very thick,rounded corners, 
    intersection segments={of=pathone and pathtwo,
    sequence=L1--R2 L3}];
  \fi   
\end{tikzpicture}

\end{document}

enter image description here

Shifting the circle down with \pgfmathsetmacro\CY{5} yields.

enter image description here

Note that the intersection segments have to be drawn outside the scope.

And here is a code that finds out where the intersections are. DISCLAIMER: It does not work if the circle goes through the rounded corners. The path you are most likely after is \mypathA arc(\angleA:\angleB:\CR) --\mypathB.

\documentclass{standalone}
\usepackage[T1]{fontenc}
\usepackage{tikz}
\usepackage{graphicx}
\usetikzlibrary{intersections,calc}
\makeatletter
% from https://tex.stackexchange.com/q/56353/121799
\newcommand{\gettikzxy}[3]{%
  \tikz@scan@one@point\pgfutil@firstofone#1\relax
  \edef#2{\the\pgf@x}%
  \edef#3{\the\pgf@y}%
}
\makeatother  
\def\mytolerance{0.2}% tolerance for comparing coordinates
\begin{document}
\begin{tikzpicture}
\pgfmathsetmacro\minX{2}
\pgfmathsetmacro\maxX{10}
\pgfmathsetmacro\minY{4}
\pgfmathsetmacro\maxY{10}
\pgfmathsetmacro\CX{9}
\pgfmathsetmacro\CY{9}
\pgfmathsetmacro\CR{2}
\pgfmathsetmacro\Roundness{0.2}
\begin{scope} [local bounding box=BoxWest]
\def\pathone{(.5*\maxX + .5*\minX,\maxY) 
    -- (-\Roundness + \maxX,\maxY)
    arc (90:0:\Roundness)
 -- (\maxX,\minY +\Roundness)
    arc (360:270:\Roundness)
    -- (.5*\maxX+ .5*\minX,\minY )}
    \path [name path=pathone, draw=green] \pathone;         
    \path [name path=pathtwo, draw=blue](\CX,\CY)
    circle (\CR);
    \path [name intersections={of=pathone and pathtwo,name=myint,total=\tot}]
  \pgfextra{
  \pgfmathtruncatemacro{\NonTriv}{ifthenelse(\tot>1,1,0)}% check if there 
  \ifnum\NonTriv=1\relax
  \gettikzxy{(.5*\maxX + .5*\minX,\maxY)}{\tmpx}{\yplus}
  \gettikzxy{(\maxX,0)}{\xmax}{\tmpy}
  \gettikzxy{(.5*\maxX+ .5*\minX,\minY )}{\tmpx}{\yminus}
  \foreach \X in {1,...,\tot}
  {
    \gettikzxy{(myint-\X)}{\myx}{\myy}
    \gettikzxy{(\CX,\CY)}{\circX}{\circY}
    \ifnum\X=1
    \pgfmathparse{mod(720+atan2(+\myy-\circY,+\myx-\circX),360)}
    \xdef\angleA{\pgfmathresult}
    %\typeout{angle\space A:\angleA}
    \else
    \pgfmathparse{mod(720+atan2(+\myy-\circY,+\myx-\circX),360)}
    \xdef\angleB{\pgfmathresult}
    %\typeout{angle\space B:\angleB}
    \fi 
    \pgfmathtruncatemacro{\isontop}{ifthenelse(abs(\myy-\yplus)<\mytolerance,1,0)}
    \ifnum\isontop=1\relax%
    %\node at (myint-\X) {\X\ is on top}; 
    \ifnum\X=1
    \xdef\mypathA{(.5*\maxX + .5*\minX,\maxY)  -- ($(\CX,\CY)+(\angleA:\CR)$)}
    \else
    \xdef\mypathB{($(\CX,\CY)+(\angleB:\CR)$) -- (-\Roundness + \maxX,\maxY)
    arc (90:0:\Roundness) -- (\maxX,\minY +\Roundness)    
    arc (360:270:\Roundness)
    -- (.5*\maxX+ .5*\minX,\minY )}
    \fi
    \fi%
    \pgfmathtruncatemacro{\isonbottom}{ifthenelse(abs(\myy-\yminus)<\mytolerance,1,0)}
    \ifnum\isonbottom=1\relax%
    %\node at (myint-\X) {\X\ is on bottom}; 
    \ifnum\X=1
    \xdef\mypathA{(.5*\maxX + .5*\minX,\maxY) -- (-\Roundness + \maxX,\maxY)
    arc (90:0:\Roundness)
 -- (\maxX,\minY +\Roundness)
    arc (360:270:\Roundness)
    --  ($(\CX,\CY)+(\angleA:\CR)$)}
    \else
    \xdef\mypathB{($(\CX,\CY)+(\angleB:\CR)$) -- (.5*\maxX+ .5*\minX,\minY )}
    \fi
    \fi%
    \pgfmathtruncatemacro{\isonright}{ifthenelse(abs(\myx-\xmax)<\mytolerance,1,0)}
    \ifnum\isonright=1\relax%
    %\node at (myint-\X) {\X\ is on right}; 
    \ifnum\X=1
    \xdef\mypathA{(.5*\maxX + .5*\minX,\maxY)-- (-\Roundness + \maxX,\maxY)
    arc (90:0:\Roundness)
 --  ($(\CX,\CY)+(\angleA:\CR)$)
    }
    \else
    \xdef\mypathB{($(\CX,\CY)+(\angleB:\CR)$) -- (\maxX,\minY +\Roundness)    
    arc (360:270:\Roundness)
    -- (.5*\maxX+ .5*\minX,\minY )}
    \fi
    \fi%
    %\typeout{\X : \myx,\myy,\yplus,\yminus,\xmax}
  }
  %\typeout{\mypathA arc(\angleA:\angleB:\CR) --\mypathB}
  \draw[red] \mypathA arc(\angleA:\angleB:\CR) --\mypathB ;
  \else
  \fi
  };
\end{scope}
\end{tikzpicture}
\end{document}

enter image description here

8
  • I need the code that generates the path since I'm using it as an input to a command that needs the path. the command I want to use the generated path in is \shapeparnode.
    – M.M.
    Mar 26, 2018 at 15:07
  • @M.M. If I were you I'd rather rewrite the \shapeparnode macro in such a way that it reuses existing paths. And you may also want to tell people what you really intend to do with these code pieces.
    – user121799
    Mar 26, 2018 at 15:21
  • I'm taking your advice on rewriting the \shapeparnode. The problem is when I reuse the path already generated, I can't shift it even with shifting the entire scope. Can you tell me why it is not working? \path[name path global=leftpath, draw=orange, very thick] (\minX,\minY) -- (\minX,\maxY); \newcommand\shapeuse[2]{ \begin{scope}[local bounding box=leftbb, shift={(#2,0)}] \draw[use path=#1, yellow]; \end{scope} } \shapeuse{leftpath}{12}
    – M.M.
    Mar 26, 2018 at 16:16
  • @M.M. I guess it's the same reason why you cannot draw the intersection segments inside the scope. TikZ works internally with absolute coordinates, and in these rather low-level routines .
    – user121799
    Mar 26, 2018 at 16:43
  • @M.M. I added an alternative. But before I drown in cases, please tell me what the deformations of the path are.
    – user121799
    Mar 26, 2018 at 16:54

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .