我正在尝试设计一个顶部和底部具有半圆形截面的盒子,如下所示:
如果文本足够小,则旨在缩小到给定的圆圈\Radius
(而不是更小的圆圈):
理想的解决方案是如果tcolorbox
可以用来产生这个,但是在文档中没有看到有关圆形的任何内容\parshape
。
笔记:
生成上面第一幅图像的代码如下平均能量损失,但也存在一些问题,包括:
- 底部
\parshape
已手动应用到正确的位置。 \PaperHeight
通过反复试验来确定。目标是使高度增加(或减少到)2\Radius
以容纳所有内容一这样的框(即没有多页问题)。- 标题应能容纳 2 行。如果超过 2 行,则无法正常工作。
参考:
- 如何指定一个很长的页面?。
- 如何定义固定宽度的页面,但长度>某个最小长度,但仅限于需要的长度。
- 自动增加 PDF 页面高度
- 自动化固定宽度页面,长度>某个最小长度,但仅达到所需的长度
- 固定最小高度的 mdframed 框
代码:
\documentclass{article}
\usepackage{lipsum}
\usepackage{tikz}
\usepackage[protrusion=false]{microtype}
%\usepackage{showframe}
\usepackage[mathlines]{lineno}
\linenumbers
\newcommand*{\Radius}{1.75in}
\newcommand*{\Margins}{2pt}
\newcommand*{\ExtraLeftMargin}{0cm}% Set to 0.5cm if want to see line numbers
\newcommand*{\PaperHeight}{12.5cm}%<----- This is tweaked for this example
\newlength{\TextWidth}
\newlength{\PaperWidth}
\pgfmathsetlength{\TextWidth}{2*\Radius}
\pgfmathsetlength{\PaperWidth}{\TextWidth+2*\Margins}
\usepackage[
paperwidth=\dimexpr\PaperWidth+\ExtraLeftMargin\relax,
paperheight=\PaperHeight,
left=\dimexpr\Margins+\ExtraLeftMargin\relax,
right=\Margins,
top=\Margins,
bottom=\Margins,
]{geometry}
\tikzset{Frame Border Style/.style={thick, draw=red}}
\tikzset{Frame Fill Style/.style={fill=green!15}}
\tikzset{Frame Title Rule Style/.style={magenta, thin}}
\tikzset{Frame Title Fill Style/.style={fill=yellow!25}}
\newcommand*{\ExternalBorder}[1]{%
\draw [#1]
([shift={(0.5*\ExtraLeftMargin-\Radius,-\Radius-\Margins)}]current page.north)
arc [start angle=180, end angle=0, radius=\Radius]
-- ([shift={(0.5*\ExtraLeftMargin+\Radius,\Radius+\Margins)}]current page.south)
arc [start angle=0, end angle=-180, radius=\Radius]
-- cycle
;
}%
\newcommand*{\TitleAndExternalBorder}[1]{%
\noindent
\begin{tikzpicture}[remember picture,overlay]
\ExternalBorder{Frame Border Style, Frame Fill Style}
\begin{scope}%% ------------------------------------ Title
\clip
([shift={(0.5*\ExtraLeftMargin,-\Radius-\Margins)}]current page.north)
circle (\Radius);
\draw [Frame Title Rule Style, Frame Title Fill Style]
([shift={(-2*\Radius-\Margins+0.20*\TextWidth,-2.25*\baselineskip)}]current page.north east)
rectangle ++(0.60*\TextWidth,2.25*\baselineskip-\Margins)
;
\end{scope}
\ExternalBorder{Frame Border Style}
\end{tikzpicture}%
\TitleShape\begingroup\centering\textbf{#1}\par\endgroup%
\TopSemiCircleParshape%
}
\newcommand*{\TitleShape}{%
\parshape 2
0.40\hsize 0.20\hsize
0.26\hsize 0.48\hsize
}%
\newcommand*{\TopSemiCircleParshape}{%
\parshape 9
%% First two lines used by title
%0.40\hsize 0.20\hsize
%0.26\hsize 0.48\hsize
0.20\hsize 0.60\hsize
0.14\hsize 0.72\hsize
0.10\hsize 0.80\hsize
0.07\hsize 0.86\hsize
0.05\hsize 0.90\hsize
0.03\hsize 0.94\hsize
0.025\hsize 0.95\hsize
0.01\hsize 0.99\hsize
0.00\hsize 1.00\hsize
}
\newcommand*{\BotSemiCircleParshape}{%
\parshape 11
0.00\hsize 1.00\hsize
0.01\hsize 0.99\hsize
0.025\hsize 0.95\hsize
0.03\hsize 0.94\hsize
0.05\hsize 0.90\hsize
0.07\hsize 0.86\hsize
0.10\hsize 0.80\hsize
0.14\hsize 0.72\hsize
0.20\hsize 0.60\hsize
0.26\hsize 0.48\hsize
0.40\hsize 0.20\hsize
}
\newcommand{\TextA}{%
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Etiam sem ante, efficitur eget diam quis, lacinia sollicitudin elit. Donec tempor sodales finibus. Fusce accumsan laoreet lorem, eget lacinia urna. Phasellus ornare nibh quis metus dignissim aliquam. Vestibulum hendrerit augue at libero dignissim cursus. Vestibulum tristique metus vitae sem sagittis gravida. Aliquam commodo arcu quam, at congue ex commodo quis. Ut dapibus, quam id suscipit vulputate, orci dolor lobortis lectus, in pellentesque ante est sit amet odio. Integer pretium iaculis sapien sit amet sagittis. Sed sagittis libero libero, eu tempus neque malesuada quis. Aliquam id mauris ac enim tincidunt aliquet nec sit amet odio. In ultricies in nulla id dictum. Nulla facilisi. Proin aliquet semper odio, sit amet eleifend ante.}
\newcommand{\TextB}{%
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Etiam sem ante, efficitur eget diam quis, lacinia sollicitudin elit. Donec tempor sodales finibus. Fusce accumsan laoreet lorem, eget lacinia urna. Phasellus ornare nibh quis metus dignissim aliquam. Vestibulum hendrerit augue at libero dignissim cursus. Vestibulum tristique metus vitae sem sagittis gravida. Aliquam commodo arcu quam, at congue ex commodo quis. Ut dapibus, quam id suscipit vulputate, orci dolor lobor\dots}
\newenvironment{MyRoundedBox}[1]{%
%% #1 = Title
\sloppy\TitleAndExternalBorder{#1}%
}{}%
\begin{document}%
\begin{MyRoundedBox}{My Lipsum Title}
\noindent\TextA
\par\BotSemiCircleParshape\TextB\par
\end{MyRoundedBox}%
\end{document}
答案1
为了简化操作,我删除了所有 TikZ 装饰,但您可以恢复它们。我还重命名了一些宏,并删除了\parshape
一些宏以方便重复使用。
还要注意,现在\TextA
和\TextB
已合并到\Text
(这是客观的),但其中的段落是用模拟的\newline
,以不取消当前的 parshape。
整个代码旨在产生一个单一的 parshape:顶部圆、中间区域、底部圆。
\documentclass{article}
\newcommand*{\TitleParshapeLines}{%
% \parshape 2
0.40\hsize 0.20\hsize
0.26\hsize 0.48\hsize
}%
\newcommand*{\TopSemiCircleParshapeLines}{%
% \parshape 9
0.20\hsize 0.60\hsize
0.14\hsize 0.72\hsize
0.10\hsize 0.80\hsize
0.07\hsize 0.86\hsize
0.05\hsize 0.90\hsize
0.03\hsize 0.94\hsize
0.025\hsize 0.95\hsize
0.01\hsize 0.99\hsize
0.00\hsize 1.00\hsize
}
\newcommand*{\BotSemiCircleParshapeLines}{%
% \parshape 11
0.00\hsize 1.00\hsize
0.01\hsize 0.99\hsize
0.025\hsize 0.95\hsize
0.03\hsize 0.94\hsize
0.05\hsize 0.90\hsize
0.07\hsize 0.86\hsize
0.10\hsize 0.80\hsize
0.14\hsize 0.72\hsize
0.20\hsize 0.60\hsize
0.26\hsize 0.48\hsize
0.40\hsize 0.20\hsize
}
\newcommand{\Text}{%
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Etiam sem
ante, efficitur eget diam quis, lacinia sollicitudin elit. Donec
tempor sodales finibus. Fusce accumsan laoreet lorem, eget lacinia
urna. Phasellus ornare nibh quis metus dignissim aliquam. Vestibulum
hendrerit augue at libero dignissim cursus. Vestibulum tristique
metus vitae sem sagittis gravida. Aliquam commodo arcu quam, at
congue ex commodo quis. Ut dapibus, quam id suscipit vulputate, orci
dolor lobortis lectus, in pellentesque ante est sit amet odio.
Integer pretium iaculis sapien sit amet sagittis. Sed sagittis
libero libero, eu tempus neque malesuada quis. Aliquam id mauris ac
enim tincidunt aliquet nec sit amet odio. In ultricies in nulla id
dictum. Nulla facilisi. Proin aliquet semper odio, sit amet eleifend
ante.\newline
\hspace*{\parindent}%
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Etiam sem
ante, efficitur eget diam quis, lacinia sollicitudin elit. Donec
tempor sodales finibus. Fusce accumsan laoreet lorem, eget lacinia
urna. Phasellus ornare nibh quis metus dignissim aliquam. Vestibulum
hendrerit augue at libero dignissim cursus. Vestibulum tristique
metus vitae sem sagittis gravida. Aliquam commodo arcu quam, at
congue ex commodo quis. Ut dapibus, quam id suscipit vulputate, orci
dolor lobor\dots
}
\newcommand*{\Radius}{1.75in}
\newcommand*{\Margins}{2pt}
\newcommand*{\ExtraLeftMargin}{0cm}% Set to 0.5cm if want to see line numbers
\newcommand\TextWidth{}
\edef\TextWidth{\the\dimexpr2\dimexpr\Radius}
\newcommand\PaperWidth{}
\edef\PaperWidth{\the\dimexpr\TextWidth+2\dimexpr\Margins}
\setbox0\vbox{\hsize\TextWidth\relax
\sloppy\everypar{}\parskip0pt\relax
\parshape
21
\TopSemiCircleParshapeLines
\BotSemiCircleParshapeLines
0pt \hsize
\noindent\Text
\par\xdef\NbOfTextLines{\the\prevgraf}%
}
\typeout{USING NBOFLINES = \NbOfTextLines}
%\newcommand*{\PaperHeight}{12.5cm}%<----- This is tweaked for this example
\newcommand\PaperHeight{}
% I assume here Title on 2 lines
\edef\PaperHeight{\the\dimexpr\numexpr2+\NbOfTextLines\relax\baselineskip}
\typeout{USING PAPERHEIGHT = \PaperHeight}
\usepackage[
paperwidth=\dimexpr\PaperWidth+\ExtraLeftMargin\relax,
paperheight=\PaperHeight,
left=\dimexpr\Margins+\ExtraLeftMargin\relax,
right=\Margins,
top=\Margins,
bottom=\Margins,
]{geometry}
\usepackage{xintkernel}
\edef\TextParshapeLines{%
\TopSemiCircleParshapeLines
\romannumeral\xintreplicate{\NbOfTextLines-20}{0pt \hsize}%
\BotSemiCircleParshapeLines
}
\begin{document}
%\topskip0pt
%\vspace*{\fill}
\sloppy\parskip0pt\relax
\parshape2 \TitleParshapeLines
\begingroup\centering\textbf{My Lipsum Title}\par\endgroup
\parshape
\NbOfTextLines\space
\TextParshapeLines
\noindent\Text
\par
%\vspace*{\fill}
\thispagestyle{empty}
\end{document}
给予
这是编辑过的代码,兼容较短的文本:
\documentclass{article}
\newcommand*{\TitleParshapeLines}{%
% \parshape 2
0.40\hsize 0.20\hsize
0.26\hsize 0.48\hsize
}%
\newcommand*{\TopSemiCircleParshapeLines}{%
% \parshape 9
0.20\hsize 0.60\hsize
0.14\hsize 0.72\hsize
0.10\hsize 0.80\hsize
0.07\hsize 0.86\hsize
0.05\hsize 0.90\hsize
0.03\hsize 0.94\hsize
0.025\hsize 0.95\hsize
0.01\hsize 0.99\hsize
0.00\hsize 1.00\hsize
}
\newcommand*{\BotSemiCircleParshapeLines}{%
% \parshape 11
0.00\hsize 1.00\hsize
0.01\hsize 0.99\hsize
0.025\hsize 0.95\hsize
0.03\hsize 0.94\hsize
0.05\hsize 0.90\hsize
0.07\hsize 0.86\hsize
0.10\hsize 0.80\hsize
0.14\hsize 0.72\hsize
0.20\hsize 0.60\hsize
0.26\hsize 0.48\hsize
0.40\hsize 0.20\hsize
}
\newcommand{\Text}{%
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Etiam sem
ante, efficitur eget diam quis, lacinia sollicitudin elit. Donec
tempor sodales finibus. Fusce accumsan laoreet lorem, eget lacinia
urna. Phasellus ornare nibh quis metus dignissim aliquam. Vestibulum
hendrerit augue at libero dignissim cursus. Vestibulum tristique
metus vitae sem sagittis gravida. Aliquam commodo arcu quam, at
congue ex commodo quis. Ut dapibus, quam id suscipit vulputate, orci
dolor lobortis lectus, in pellentesque ante est sit amet odio.
Integer pretium iaculis sapien sit amet sagittis. Sed sagittis
libero libero, eu tempus neque malesuada quis. Aliquam id mauris ac
enim tincidunt aliquet nec sit amet odio. In ultricies in nulla id
dictum. Nulla facilisi. Proin aliquet semper odio, sit amet eleifend
ante.\newline
\hspace*{\parindent}%
% Lorem ipsum dolor sit amet, consectetur adipiscing elit. Etiam sem
% ante, efficitur eget diam quis, lacinia sollicitudin elit. Donec
% tempor sodales finibus. Fusce accumsan laoreet lorem, eget lacinia
% urna. Phasellus ornare nibh quis metus dignissim aliquam. Vestibulum
% hendrerit augue at libero dignissim cursus. Vestibulum tristique
% metus vitae sem sagittis gravida. Aliquam commodo arcu quam, at
% congue ex commodo quis. Ut dapibus, quam id suscipit vulputate, orci
% dolor lobor\dots
}
\newcommand*{\Radius}{1.75in}
\newcommand*{\Margins}{2pt}
\newcommand*{\ExtraLeftMargin}{0cm}% Set to 0.5cm if want to see line numbers
\newcommand\TextWidth{}
\edef\TextWidth{\the\dimexpr2\dimexpr\Radius}
\newcommand\PaperWidth{}
\edef\PaperWidth{\the\dimexpr\TextWidth+2\dimexpr\Margins}
\setbox0\vbox{\hsize\TextWidth\relax
\sloppy\everypar{}\parskip0pt\relax
\parshape
21
\TopSemiCircleParshapeLines
\BotSemiCircleParshapeLines
0pt \hsize
\noindent\Text
\par\xdef\NbOfTextLines{\the\prevgraf}%
}
\typeout{USING NBOFLINES = \NbOfTextLines}
%\newcommand*{\PaperHeight}{12.5cm}%<----- This is tweaked for this example
\newcommand\PaperHeight{}
% I assume here Title on 2 lines
\edef\PaperHeight{\the\dimexpr\numexpr2+
\ifnum\NbOfTextLines>20
\NbOfTextLines
\else 20\fi\relax\baselineskip}
\typeout{USING PAPERHEIGHT = \PaperHeight}
\usepackage[
paperwidth=\dimexpr\PaperWidth+\ExtraLeftMargin\relax,
paperheight=\PaperHeight,
left=\dimexpr\Margins+\ExtraLeftMargin\relax,
right=\Margins,
top=\Margins,
bottom=\Margins,
]{geometry}
\usepackage{xintkernel}
\edef\TextParshapeLines{%
\TopSemiCircleParshapeLines
\romannumeral\xintreplicate{\NbOfTextLines-20}{0pt \hsize}%
\BotSemiCircleParshapeLines
}
%\show\TextParshapeLines
\begin{document}
%\topskip0pt
%\vspace*{\fill}
\sloppy\parskip0pt\relax
\parshape2 \TitleParshapeLines
\begingroup\centering\textbf{My Lipsum Title}\par\endgroup
\parshape
\ifnum\NbOfTextLines>20
\NbOfTextLines
\else 20\fi\space
\TextParshapeLines
\noindent\Text
\par
%\vspace*{\fill}
\thispagestyle{empty}
\end{document}
例如:
(这个例子在模拟 parindent 之后截断了文本,但我没有检查我注释掉了什么,现在图像已经上传,我把它保留成这样,最好是在源代码中剪切上面一行或后面一行,而不是在这个愚蠢的位置)
为了引发大量的点赞,我从 OP 中原封不动地复制了 TikZ 代码。
\documentclass{article}
\usepackage{tikz}
\usepackage[protrusion=false]{microtype}
\newcommand*{\TitleParshapeLines}{%
% \parshape 2
0.40\hsize 0.20\hsize
0.26\hsize 0.48\hsize
}%
\newcommand*{\TopSemiCircleParshapeLines}{%
% \parshape 9
0.20\hsize 0.60\hsize
0.14\hsize 0.72\hsize
0.10\hsize 0.80\hsize
0.07\hsize 0.86\hsize
0.05\hsize 0.90\hsize
0.03\hsize 0.94\hsize
0.025\hsize 0.95\hsize
0.01\hsize 0.99\hsize
0.00\hsize 1.00\hsize
}
\newcommand*{\BotSemiCircleParshapeLines}{%
% \parshape 11
0.00\hsize 1.00\hsize
0.01\hsize 0.99\hsize
0.025\hsize 0.95\hsize
0.03\hsize 0.94\hsize
0.05\hsize 0.90\hsize
0.07\hsize 0.86\hsize
0.10\hsize 0.80\hsize
0.14\hsize 0.72\hsize
0.20\hsize 0.60\hsize
0.26\hsize 0.48\hsize
0.40\hsize 0.20\hsize
}
\newcommand{\Text}{%
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Etiam sem
ante, efficitur eget diam quis, lacinia sollicitudin elit. Donec
tempor sodales finibus. Fusce accumsan laoreet lorem, eget lacinia
urna. Phasellus ornare nibh quis metus dignissim aliquam. Vestibulum
hendrerit augue at libero dignissim cursus. Vestibulum tristique
metus vitae sem sagittis gravida. Aliquam commodo arcu quam, at
congue ex commodo quis. Ut dapibus, quam id suscipit vulputate, orci
dolor lobortis lectus, in pellentesque ante est sit amet odio.
Integer pretium iaculis sapien sit amet sagittis. Sed sagittis
libero libero, eu tempus neque malesuada quis. Aliquam id mauris ac
enim tincidunt aliquet nec sit amet odio. In ultricies in nulla id
dictum. Nulla facilisi. Proin aliquet semper odio, sit amet eleifend
ante.\newline
\hspace*{\parindent}%
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Etiam sem
ante, efficitur eget diam quis, lacinia sollicitudin elit. Donec
tempor sodales finibus. Fusce accumsan laoreet lorem, eget lacinia
urna. Phasellus ornare nibh quis metus dignissim aliquam. Vestibulum
hendrerit augue at libero dignissim cursus. Vestibulum tristique
metus vitae sem sagittis gravida. Aliquam commodo arcu quam, at
congue ex commodo quis. Ut dapibus, quam id suscipit vulputate, orci
dolor lobor\dots
}
\newcommand*{\Radius}{1.75in}
\newcommand*{\Margins}{2pt}
\newcommand*{\ExtraLeftMargin}{0cm}% Set to 0.5cm if want to see line numbers
\newcommand\TextWidth{}
\edef\TextWidth{\the\dimexpr2\dimexpr\Radius}
\newcommand\PaperWidth{}
\edef\PaperWidth{\the\dimexpr\TextWidth+2\dimexpr\Margins}
\setbox0\vbox{\hsize\TextWidth\relax
\sloppy\everypar{}\parskip0pt\relax
\parshape
21
\TopSemiCircleParshapeLines
\BotSemiCircleParshapeLines
0pt \hsize
\noindent\Text
\par\xdef\NbOfTextLines{\the\prevgraf}%
}
\typeout{USING NBOFLINES = \NbOfTextLines}
%\newcommand*{\PaperHeight}{12.5cm}%<----- This is tweaked for this example
\newcommand\PaperHeight{}
% I assume here Title on 2 lines
\edef\PaperHeight{\the\dimexpr\numexpr2+
\ifnum\NbOfTextLines>20
\NbOfTextLines
\else 20\fi\relax\baselineskip}
\typeout{USING PAPERHEIGHT = \PaperHeight}
\usepackage[
paperwidth=\dimexpr\PaperWidth+\ExtraLeftMargin\relax,
paperheight=\PaperHeight,
left=\dimexpr\Margins+\ExtraLeftMargin\relax,
right=\Margins,
top=\Margins,
bottom=\Margins,
]{geometry}
\usepackage{xintkernel}
\edef\TextParshapeLines{%
\TopSemiCircleParshapeLines
\romannumeral\xintreplicate{\NbOfTextLines-20}{0pt \hsize}%
\BotSemiCircleParshapeLines
}
%\show\TextParshapeLines
\tikzset{Frame Border Style/.style={thick, draw=red}}
\tikzset{Frame Fill Style/.style={fill=green!15}}
\tikzset{Frame Title Rule Style/.style={magenta, thin}}
\tikzset{Frame Title Fill Style/.style={fill=yellow!25}}
\newcommand*{\ExternalBorder}[1]{%
\draw [#1]
([shift={(0.5*\ExtraLeftMargin-\Radius,-\Radius-\Margins)}]current page.north)
arc [start angle=180, end angle=0, radius=\Radius]
-- ([shift={(0.5*\ExtraLeftMargin+\Radius,\Radius+\Margins)}]current page.south)
arc [start angle=0, end angle=-180, radius=\Radius]
-- cycle
;
}%
\newcommand*{\TikzDecorations}[1]{%
\noindent
\begin{tikzpicture}[remember picture,overlay]
\ExternalBorder{Frame Border Style, Frame Fill Style}
\begin{scope}%% ------------------------------------ Title
\clip
([shift={(0.5*\ExtraLeftMargin,-\Radius-\Margins)}]current page.north)
circle (\Radius);
\draw [Frame Title Rule Style, Frame Title Fill Style]
([shift={(-2*\Radius-\Margins+0.20*\TextWidth,-2.25*\baselineskip)}]current page.north east)
rectangle ++(0.60*\TextWidth,2.25*\baselineskip-\Margins)
;
\end{scope}
\ExternalBorder{Frame Border Style}
\end{tikzpicture}%
}
\begin{document}
%\topskip0pt
%\vspace*{\fill}
\sloppy\parskip0pt\relax
\TikzDecorations{My Lipsum Title}%
\parshape2 \TitleParshapeLines
\begingroup\centering\textbf{My Lipsum Title}\par\endgroup
\parshape
\ifnum\NbOfTextLines>20
\NbOfTextLines
\else 20\fi\space
\TextParshapeLines
\noindent\Text
\par
%\vspace*{\fill}
\thispagestyle{empty}
\end{document}
产生这个:
需要进行一些调整(似乎 Tikz 边框有点窄),但 @PeterGrill 比我更了解如何让圆圈变得更宽一些。
或者,对底部圆使用稍微修改过的 parshape 参数,稍微缩小一点。也许在包含的 Tikz 代码中进行简单的修改,但对 Peter 来说比我自己做更容易。
较短文本的情况
和
\newcommand{\Text}{%
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Etiam sem
ante, efficitur eget diam quis, lacinia sollicitudin elit. Donec
tempor sodales finibus. Fusce accumsan laoreet lorem, eget lacinia
urna. Phasellus ornare nibh quis metus dignissim aliquam. Vestibulum
hendrerit augue at libero dignissim cursus.% Vestibulum tristique
% metus vitae sem sagittis gravida.
% Aliquam commodo arcu quam, at
% congue ex commodo quis. Ut dapibus, quam id suscipit vulputate, orci
% dolor lobortis lectus, in pellentesque ante est sit amet odio.
% Integer pretium iaculis sapien sit amet sagittis. Sed sagittis
% libero libero, eu tempus neque malesuada quis. Aliquam id mauris ac
% enim tincidunt aliquet nec sit amet odio. In ultricies in nulla id
% dictum. Nulla facilisi.
Proin aliquet semper odio, sit amet eleifend
ante.\newline
\hspace*{\parindent}%
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Etiam sem
ante, efficitur eget diam quis, lacinia sollicitudin elit. Donec
tempor sodales finibus. Fusce accumsan laoreet lorem, eget lacinia
urna. Phasellus ornare nibh quis metus dignissim aliquam. Vestibulum
hendrerit augue at libero dignissim cursus. Vestibulum tristique
metus vitae sem sagittis gravida.% Aliquam commodo arcu quam, at
% congue ex commodo quis.
Ut dapibus, quam id suscipit vulputate, orci
dolor lobor\dots
}
我的感觉是,要么 parshape 参数需要进行一些调整,要么 Tikz 绘图的参数需要进行一些调整。
答案2
只是为了好玩。我现在完全改变了思路,开始使用Paul Gaborit 的回答非常令人震惊。它的一个主要优点是它充分利用了 parshape 包的全部功能。(我不敢触碰宏,尽管我很想用一种可能不那么危险的语法替换所有的 pgfextra 代码。)这个宏绝对令人惊叹的是它允许你用文本填充任意形状,而且结果看起来不错!(我没有做到的是与\centering
这些高级 par 整形方法结合使用,我不知道这是否可能或已经完成。)下面的过程如下:
- 测量/估计文本的尺寸(类似于我的评论和jfbu 的回答很好)显然这只是一个估计,可能会有偏差。
- 使用 Paul Gaborit 的惊人代码绘制标题形状并用文本填充。
- 绘制下方形状并填充。
这是代码。
\documentclass[border=3.14mm]{standalone}
\usepackage{lmodern}
\usepackage[T1]{fontenc}
\usepackage{shapepar}
\usepackage{microtype}
\usepackage{lipsum}
\usepackage{expl3}
\ExplSyntaxOn% from https://tex.stackexchange.com/a/16192/121799
\cs_new_eq:NN \Repeat \prg_replicate:nn
\ExplSyntaxOff
\usepackage{tikz}
\usetikzlibrary{calc,fit,intersections}
% from one of the most stunning answers I have seen: https://tex.stackexchange.com/a/68740/121799
\def\shapeparnodeaccuracy{2}
\newcommand\shapeparnode[6][]{
% 6 parameters:
% style for node (default:empty),
% h margin, v margin, left path, right path, text (just one paragraph!)
% name left and right paths and compute there bounding boxes
\begin{scope}[local bounding box=leftbb,xshift=#2]
\path[name path global=left] #4;
\end{scope}
\node[inner ysep=-#3,inner xsep=0pt,fit=(leftbb)](leftbb){};
\begin{scope}[local bounding box=rightbb,xshift=-#2]
\path[name path global=right] #5;
\end{scope}
\node[inner ysep=-#3,inner xsep=0pt,fit=(rightbb)](rightbb){};
% global bounding box
\path let
\p1=(leftbb.north west), \p2=(leftbb.south west),
\p3=(rightbb.north east), \p4=(rightbb.south east)
in
\pgfextra{
\pgfmathsetmacro{\ymin}{(\y1 < \y3) ? \y1 : \y3}
\pgfmathsetmacro{\ymax}{(\y2 > \y4) ? \y2 : \y4}
\typeout{ymin \ymin}
\typeout{ymax \ymax}
} node[inner sep=0,fit={(\x1,\ymin pt)(\x3,\ymax pt)}](mybb){};
% compute nb steps
\path let \p1=(mybb.north), \p2=(mybb.south) in
\pgfextra{
\pgfmathsetmacro{\fnthght}{1em/\shapeparnodeaccuracy}
\pgfmathtruncatemacro{\nbsteps}{(\y1-\y2)/\fnthght}
\xdef\nbsteps{\nbsteps}
\typeout{nb steps \nbsteps}
};
% horizontal references
\path (mybb.north) -- (mybb.south)
\foreach \cnt in {0,1,...,\nbsteps}{
\pgfextra{\pgfmathsetmacro{\pos}{\cnt/\nbsteps}}
coordinate[pos=\pos] (ref \cnt)
};
% left and right boundaries coordinates
\foreach \cnt in {0,1,...,\nbsteps}{
% an horizontal line from left to right
\path[name path=ltor]
(mybb.west |- ref \cnt) -- (mybb.east |- ref \cnt);
% same line from right to left
\path[name path=rtol]
(mybb.east |- ref \cnt) -- (mybb.west |- ref \cnt);
% left boundary
\path[name intersections={of=rtol and left,by={l \cnt},sort by=rtol}];
% right boundary
\path[name intersections={of=ltor and right,by={r \cnt},sort by=ltor}];
}
% start point (and initial value of boundshape)
\path let \p1=(l 0) in
\pgfextra{
\pgfmathsetmacro{\xstart}{\x1}
\xdef\boundshape{{0}{0}b{\xstart}}
\xdef\xmin{\xstart}
\xdef\xmax{\xstart}
};
% top and bottom
\path let \p1=(l 0), \p2=(l \nbsteps) in
\pgfextra{
\pgfmathsetmacro{\ystart}{\y1}\xdef\ystart{\ystart}
\pgfmathsetmacro{\yending}{\y2}\xdef\yending{\yending}
};
% incremental definition of boundshape
\foreach \cnt in {0,1,...,\nbsteps}{
\path let \p1=(l \cnt), \p2=(r \cnt) in
\pgfextra{
\pgfmathsetmacro{\start}{\x1}
\pgfmathsetmacro{\len}{\x2-\x1}
\pgfmathsetmacro{\ypos}{\cnt/\nbsteps*(\ystart - \yending)}
{\let\\=\relax \xdef\boundshape{\boundshape\\{\ypos}t{\start}{\len}}}
\pgfmathsetmacro{\xmin}{(\xmin < \start) ? \xmin : \start}
\xdef\xmin{\xmin}
\pgfmathsetmacro{\xmax}{(\xmax > \start + \len) ? \xmax : \start + \len}
\xdef\xmax{\xmax}
};
}
% draw the node with text in a shapepar
\pgfmathsetmacro{\ymax}{\ystart - \yending}
{\let\\=\relax \xdef\boundshape{\boundshape\\{\ymax}e{0}}}
\node[#1,text width=\xmax pt - \xmin pt,align=flush left,
anchor=north west,inner sep=0]
at (mybb.north west -| \xmin pt,0)
{\Shapepar[1pt]{\boundshape}#6\par};
}
\newcommand*{\Radius}{1.75in}
\newcommand*{\FullCircleParshape}[1][23]{%
\pgfmathtruncatemacro{\X}{#1-21}
\parshape #1
0.40\hsize 0.20\hsize
0.26\hsize 0.48\hsize
0.20\hsize 0.60\hsize
0.14\hsize 0.72\hsize
0.10\hsize 0.80\hsize
0.07\hsize 0.86\hsize
0.05\hsize 0.90\hsize
0.03\hsize 0.94\hsize
0.025\hsize 0.95\hsize
0.01\hsize 0.99\hsize
\ifnum\X>0
\Repeat{\X}{0.00\hsize 1.00\hsize}
\fi
0.01\hsize 0.99\hsize
0.025\hsize 0.95\hsize
0.03\hsize 0.94\hsize
0.05\hsize 0.90\hsize
0.07\hsize 0.86\hsize
0.10\hsize 0.80\hsize
0.14\hsize 0.72\hsize
0.20\hsize 0.60\hsize
0.26\hsize 0.48\hsize
0.40\hsize 0.20\hsize
0.00\hsize 1.00\hsize
}
\pgfmathsetmacro{\myTextWidth}{(2*\Radius-2em)/1pt}
\newlength\TextWidth
\setlength\TextWidth{\myTextWidth pt}
\newlength\TotalHeight
\newlength\TitleHeight
\newsavebox\tmpbox
\newsavebox\titlebox
\newcommand{\EstimateDimensionsOfOvershootingParShape}[2]{%
\savebox\tmpbox{\parbox[b]{\TextWidth}{\FullCircleParshape[23]\begingroup%
\centering\textbf{#1}\newline #2\par%
\endgroup}}%
\setlength\TotalHeight{\ht\tmpbox}
\savebox\titlebox{\parbox[b]{3.5in}{\FullCircleParshape[23]\begingroup%
\centering\textbf{#1}\par\endgroup}}%
\setlength\TitleHeight{\ht\titlebox}
}
\def\mytext{Lorem ipsum dolor sit amet, consectetur adipiscing
elit. Donec a diam lectus. Sed sit amet ipsum mauris. Maecenas congue
ligula ac quam viverra nec consectetur ante hendrerit. Donec et mollis
dolor. Praesent et diam eget libero egestas mattis sit amet vitae
augue. Nam tincidunt congue enim, ut porta lorem lacinia
consectetur. $x = y + z$ arcu vehicula ultricies a non tortor. Lorem
ipsum dolor sit amet, consectetur adipiscing elit. Aenean ut gravida
lorem. \textbf{Ut turpis felis}, pulvinar a semper sed, adipiscing id
dolor. Pellentesque auctor nisi id magna consequat sagittis. Curabitur
dapibus enim sit amet elit pharetra tincidunt feugiat nisl
imperdiet. Ut convallis libero in urna ultrices accumsan. Donec sed
odio eros. Donec viverra mi quis quam pulvinar at malesuada arcu
rhoncus. \emph{\large Cum sociis natoque} penatibus et magnis dis
parturient montes, nascetur ridiculus mus. In rutrum accumsan
ultricies. Mauris vitae nisi at sem facilisis semper ac in
est. Vivamus fermentum semper porta. Nunc diam velit, adipiscing ut
tristique vitae, sagittis vel odio. Maecenas convallis ullamcorper
ultricies.}
\def\mytitle{This here is a very long title!}
\begin{document}%
\EstimateDimensionsOfOvershootingParShape{\mytitle}{\mytext}
%\typeout{\the\TotalHeight,\the\TitleHeight}
\tikzset{Frame Border Style/.style={thick, draw=red}}
\tikzset{Frame Fill Style/.style={fill=green!15}}
\tikzset{Frame Title Rule Style/.style={magenta, thin}}
\tikzset{Frame Title Fill Style/.style={fill=yellow!25}}
\begin{tikzpicture}
\pgfmathsetmacro{\myangle}{acos((\Radius-\the\TitleHeight-15pt)/\Radius)}
\def\pathone{(0,-2pt) arc(90:90+\myangle:0.9*\Radius)}%
\def\pathtwo{(0,-2pt) arc(90:90-\myangle:0.9*\Radius)}%
\begin{scope}[local bounding box=top]
\path (0,0) arc(90:90+\myangle:\Radius) coordinate (start1);
\path (0,0) arc(90:90-\myangle:\Radius) coordinate (start2);
\draw [Frame Title Rule Style,Frame Title Fill Style]
(start2) -- (start1) arc(90+\myangle:90-\myangle:\Radius);
\shapeparnode[text=blue,font=\bfseries]
{1em}{.5em}{\pathone}{\pathtwo}{\mytitle}%
\end{scope}
\pgfmathsetmacro{\ydist}{max(\TotalHeight-\TitleHeight-2*\Radius,0)}
\def\pathone{(start1) arc(90+\myangle:180:{0.9*\Radius} and \Radius)
-- ++(0,-\ydist*1pt) arc(180:270:{0.9*\Radius} and \Radius)}%
\def\pathtwo{(start2) arc(90-\myangle:0:{0.9*\Radius} and \Radius)
-- ++(0,-\ydist*1pt) arc(0:-90:{0.9*\Radius} and \Radius)}%
\begin{scope}[local bounding box=bottom]
\draw[Frame Border Style,Frame Fill Style] (start1) arc(90+\myangle:180:\Radius)
coordinate (aux3)
-- ++(0,-\ydist*1pt-12pt) arc(180:360:\Radius) coordinate (aux4)
-- (aux3-|aux4) arc(0:90-\myangle:\Radius) -- cycle;
\shapeparnode[text=blue]
{1em}{.5em}{\pathone}{\pathtwo}{\mytext}%
\end{scope}
\end{tikzpicture}
\end{document}
旧答案:我似乎最终使用了与 jfbu 类似的策略,我刚刚看到了他的答案。常见的问题似乎是,如果以这种方式使用,parshape 塑造段落/文本的方式并不总是很好。此代码的作用是测量文本的高度,然后在其周围绘制边界。(不,给文本加阴影没有问题,我只是没有这样做。可以通过填充形状并使用适当的混合模式,或者在 中放置适当的保存框来完成。)我的答案肯定比 jfbu 的答案弱的一个方面是它如何处理太少的文本。我的代码根本没有处理这个问题。我没有处理这个问题的原因是我想知道在这种情况下该怎么做。就我个人而言,在这种情况下,我只会使用较小尺寸的圆圈(而不是部分填充的大圆圈)。另一个区别是我使用了库tikzmark
。这有助于避免文本超出范围。这肯定可以改进。
\documentclass{article}
\usepackage{expl3}
\ExplSyntaxOn% from https://tex.stackexchange.com/a/16192/121799
\cs_new_eq:NN \Repeat \prg_replicate:nn
\ExplSyntaxOff
\usepackage{lipsum}
\usepackage{tikz}
\usetikzlibrary{tikzmark,intersections}
\usepackage[protrusion=false]{microtype}
\usepackage[mathlines]{lineno}
\linenumbers
\newcommand*{\Radius}{1.75in}
\newcommand*{\Margins}{2pt}
\newcommand*{\ExtraLeftMargin}{0cm}% Set to 0.5cm if want to see line numbers
\newcommand*{\PaperHeight}{12.5cm}%<----- This is tweaked for this example
\newlength{\TextWidth}
\newlength{\PaperWidth}
\pgfmathsetlength{\TextWidth}{2*\Radius}
\pgfmathsetlength{\PaperWidth}{\TextWidth+2*\Margins}
\usepackage[
paperwidth=\dimexpr\PaperWidth+\ExtraLeftMargin\relax,
paperheight=\PaperHeight,
left=\dimexpr\Margins+\ExtraLeftMargin\relax,
right=\Margins,
top=\Margins,
bottom=\Margins,
]{geometry}
\tikzset{Frame Border Style/.style={thick, draw=red}}
\tikzset{Frame Fill Style/.style={fill=green!15}}
\tikzset{Frame Title Rule Style/.style={magenta, thin}}
\tikzset{Frame Title Fill Style/.style={fill=yellow!25}}
\newcommand*{\FullCircleParshape}[1][23]{%
\pgfmathtruncatemacro{\X}{#1-21}
\parshape #1
0.40\hsize 0.20\hsize
0.26\hsize 0.48\hsize
0.20\hsize 0.60\hsize
0.14\hsize 0.72\hsize
0.10\hsize 0.80\hsize
0.07\hsize 0.86\hsize
0.05\hsize 0.90\hsize
0.03\hsize 0.94\hsize
0.025\hsize 0.95\hsize
0.01\hsize 0.99\hsize
\ifnum\X>0
\Repeat{\X}{0.00\hsize 1.00\hsize}
\fi
0.01\hsize 0.99\hsize
0.025\hsize 0.95\hsize
0.03\hsize 0.94\hsize
0.05\hsize 0.90\hsize
0.07\hsize 0.86\hsize
0.10\hsize 0.80\hsize
0.14\hsize 0.72\hsize
0.20\hsize 0.60\hsize
0.26\hsize 0.48\hsize
0.40\hsize 0.20\hsize
0.00\hsize 1.00\hsize
}
\newcommand{\TextA}{%
Koalae et marmottae et duckae, lorem ipsum dolor sit amet, consectetur adipiscing elit. Etiam sem ante, efficitur eget diam quis, lacinia sollicitudin elit. Donec tempor sodales finibus. Fusce accumsan laoreet lorem, eget lacinia urna. Phasellus ornare nibh quis metus dignissim aliquam. Vestibulum hendrerit augue at libero dignissim cursus. Vestibulum tristique metus vitae sem sagittis gravida. Aliquam commodo arcu quam, at congue ex commodo quis. Ut dapibus, quam id suscipit vulputate, orci dolor lobortis lectus, in pellentesque ante est sit amet odio. Integer pretium iaculis sapien sit amet sagittis. Sed sagittis libero libero, eu tempus neque malesuada quis. Aliquam id mauris ac enim tincidunt aliquet nec sit amet odio. In ultricies in nulla id dictum. Nulla facilisi. Proin aliquet semper odio, sit amet eleifend ante.}
\newcommand{\TextB}{%
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Etiam sem ante, efficitur eget diam quis, lacinia sollicitudin elit. Donec tempor sodales finibus. Fusce accumsan laoreet lorem, eget lacinia urna. Phasellus ornare nibh quis metus dignissim aliquam. Vestibulum hendrerit augue at libero dignissim cursus. Vestibulum tristique metus vitae sem sagittis gravida. Aliquam commodo arcu quam, at congue ex commodo quis. Ut dapibus, quam id suscipit vulputate, orci dolor lobor\dots}
\newlength\TotalHeight
\newlength\NewHeight
\newsavebox\tmpbox
\newcounter{obox}
\newcommand{\OvershootingParShape}[2]{%
\stepcounter{obox}
\savebox\tmpbox{\parbox[b]{\textwidth}{\FullCircleParshape[23]\begingroup%
\centering\textbf{#1}\newline #2\par%
\endgroup}}%
\setlength\TotalHeight{\ht\tmpbox}
\pgfmathtruncatemacro{\myl}{25+(\TotalHeight-258)/12}
\typeout{\myl}
\savebox\tmpbox{\parbox[b]{\textwidth}{\FullCircleParshape[\myl]\begingroup%
\centering\textbf{#1}\newline #2\par%
\endgroup}}%
\setlength\NewHeight{\ht\tmpbox}
\typeout{\the\TotalHeight -> \the\NewHeight}
\ifnum\myl<21
\typeout{Too\space little\space text.\space
Macro\space is\space not\space (yet)\space made\space for\space that.}
\fi
\FullCircleParshape[\myl]\begingroup%
\centering\textbf{\tikzmark{top-\theobox}#1}\newline \tikzmark{tbottom-\theobox}#2\par%
\endgroup
\begin{tikzpicture}[overlay,remember picture]
\pgfmathsetmacro{\myheight}{12*(\myl-24)*1pt+258*1pt}
\path ([yshift=12pt]pic cs:top-\theobox) coordinate (top)
([yshift=-\myheight-24pt]top) coordinate (bottom)
([yshift=+9pt]pic cs:tbottom-\theobox) coordinate (tbottom);
\draw[Frame Border Style,name path=oval] (current page.center |-top) arc(90:0:\Radius)
coordinate (aux1)
-- ([yshift=\Radius]bottom -|aux1) arc(0:-180:\Radius) coordinate(aux2)
-- ([yshift=-\Radius]top -|aux2) arc(180:90:\Radius) -- cycle;
\path[name path=hori] (aux1 |- tbottom) -- (aux2 |- tbottom);
\draw[Frame Border Style,name intersections={of=oval and hori,by={aux3,aux4}}]
(aux3) -- (aux4);
\end{tikzpicture}}
\begin{document}%
\OvershootingParShape{This is a title of arbitrary length!}{\TextA}
\newpage
\OvershootingParShape{This is a title of arbitrary length!}{\TextB\TextB}
\end{document}