手绘草图,导入 TikZ

手绘草图,导入 TikZ

我需要重现各种 2D 和 3D 图形,例如下面显示的图形,这些图形原本是手绘的。每个图形的某些部分显然可以直接用TikZ代码完成,但其他部分,尤其是不规则的“曲线”部分,则更容易通过手绘创建。

请注意,我将修改其中一些图形并创建新的图形,这些图形既有规则的、易于编码的部分(包括数学符号),也有不规则的“曲线”部分。

我设想了一个工作流程,其中这些“弯曲”的部分是使用 iPad Pro 上的绘图应用程序构建的。

问题:是否有适用于 iPad Pro 的 iOS 应用程序,可以将手绘的“曲线”部分轻松转换为TikZ代码,然后添加到最适合直接构建的部件中TikZ?或者有更好的方法吗?

笔记:我是不是要求提供TikZ创建这些图形的代码!相反,我问的是导致该代码的技术方法。

社区

功能

同伦

克莱因瓶

答案1

不是一个答案,只是为了好玩。我知道你没有要求代码。这主要是为了证实用基本 Ti 绘制这些不规则形状并不太难的说法Z 语法。以下是列表中两个图形的复制品。

\documentclass[tikz,border=3.14mm]{standalone}
\usetikzlibrary{calc,intersections,arrows.meta}
\usepackage{pgfplots}
\usepgfplotslibrary{fillbetween}
\begin{document}
\begin{tikzpicture}[long dash/.style={dash pattern=on 10pt off 2pt}]
\draw[ultra thick,long dash,name path=left,fill=orange!30] plot[smooth cycle] coordinates 
{(0.3,-2) (-1,-3) (-8,-1.2) (-8.8,-0.2) (-7,0.6) (-1,-0.6)};
\draw[ultra thick,long dash,name path=left bottom] plot[smooth cycle] coordinates 
{(-8,-2.8) (-9,-2.5) (-8.5,-1) (-7,0) (-6,1.7) (-5,1.7) (-4,-0) (-5.5,-2)};
\draw[ultra thick,long dash,name path=left top] plot[smooth cycle] coordinates 
{(-7.2,-1) (-7.8,1) (-6.7,2) (-5.5,1) (-5,0) (-5.4,-1) (-6,-1.2)};
\path [%draw,blue,ultra thick,
    name path=left arc,
    intersection segments={
        of=left top and left,
        sequence={A1--B1}
    }];
\path [%draw,red,ultra thick,
    fill=red!30,
    name path=left blob,
    intersection segments={
        of=left bottom and left arc,
        sequence={A1--B0}
    }];
\node[fill,circle,label=above right:$F$] at (-6.1,-0.3){};  
\node at (-2.5,-1.8){$V_y$};    
% right part
\path[fill=orange!30] plot[smooth cycle] coordinates 
{(-1.3,2) (-0.7,3) (1,3.7) (5.2,3) (8,1.6) (8.4,1) (8,0.3) (6,0) (4,0) (2,0.3) (0,1)};
\path[fill=blue!30] plot[smooth cycle] coordinates 
{(0,-2) (-0.3,-1.5) (-0.2,0) (-0.3,1) (-1,2) (0,2.8) (3,2) (7,1) (7.3,-1)
(6,-2.3) (4,-2.3) (2,-2)};
\draw[ultra thick,long dash,name path=right top] plot[smooth cycle] coordinates 
{(-1.3,2) (-0.7,3) (1,3.7) (5.2,3) (8,1.6) (8.4,1) (8,0.3) (6,0) (4,0) (2,0.3) (0,1)};
\draw[ultra thick,name path=right] plot[smooth cycle] coordinates 
{(0,-2) (-0.3,-1.5) (-0.2,0) (-0.3,1) (-1,2) (0,2.8) (3,2) (7,1) (7.3,-1)
(6,-2.3) (4,-2.3) (2,-2)};
\draw[ultra thick,long dash,name path=middle] plot[smooth cycle] coordinates 
{(0,-3.4) (-1,-2) (-1,-0.5) (-1.5,0.4) (-1,1.6) (0,1.9) (2.1,1) (3,-1) (2.5,-3) (1,-3.7)};
\draw[ultra thick,long dash,name path=right bottom] plot[smooth cycle] coordinates 
{(1,-3) (0.6,-2) (1.2,0) (3,0.8) (6,0.8) (8.5,1) (10,0) (9,-3) (7,-3.7) (5,-3.6) (2,-3.6)};
\path[name path=circle] (5.2,1.5) arc(-30:190:4mm);
\path [%draw,red,ultra thick,
    name path=aux1,
    intersection segments={
        of=circle and right,
        sequence={B1}
    }];
\path [draw,blue!30,ultra thick,
    name path=aux2,
    intersection segments={
        of=circle and aux1,
        sequence={B0}
    }];
\node at (4.8,1.6){$U_y$};  
\node[fill,circle,label=below right:$y$] at (3.3,1.5){};    
\node[fill=blue!30] at (3.7,0){$K$};    
\end{tikzpicture}

\begin{tikzpicture}[thick]
\draw[-latex] (0,0) -- (5,0) node[right]{$s$};
\draw[-latex] (0,0) -- (0,7) node[left]{$y$};
\draw (4,0) -- (4,5.5);
\foreach \X in {1,2,4.5}
{\draw (0,\X) -- (4,\X);}
\foreach \X/\Y [count=\Z]in {0/0,3.5/t,5.5/1}
{
\ifnum\Z=1
\draw[very thick,fill] (0,\X) circle(1pt) node[left]{$(0,\Y)$} -- (4,\X) 
coordinate[midway,below] (l1) circle(1pt)
node[below right]{$(1,\Y)$};
\else
\draw[very thick,fill] (0,\X) circle(1pt) node[left]{$(0,\Y)$} -- (4,\X) 
\ifnum\Z=2
coordinate[midway,below] (l3)
\fi
\ifnum\Z=3
coordinate[midway,above] (l2)
\fi
circle(1pt)
node[right]{$(1,\Y)$};
\fi
}
\draw[fill,very thick] (1.5,3.5) circle (1pt) node[below] {$(s,t)$};
\begin{scope}[xshift=6.5cm]

 \draw[very thick] plot[smooth cycle] coordinates
 {(0,2) (0,5) (1.3,7) (5,7.9) (8.2,6) (8.3,3) (6,1.4) (2,1.2)};
 \node[circle,fill,scale=0.6] (L) at (0.5,4){};
 \node[circle,fill,scale=0.6] (R) at (7.5,4.2){};
 \foreach \X in {-45,-20,-5,45,60}
 {\pgfmathsetmacro{\Y}{180-\X+4*rnd}
 \draw (L) to[out=\X,in=\Y,looseness=1.2]  (R);
 \ifnum\X=-45
 \path  (L) to[out=\X,in=\Y,looseness=1.2] coordinate[pos=0.5,below] (r1)
 node[pos=0.6,below]{$\sigma$} (R);
 \fi
 \ifnum\X=60
\path  (L) to[out=\X,in=\Y,looseness=1.2] coordinate[pos=0.4,above] (r2)
 node[pos=0.6,above]{$\tau$} (R);
 \fi
 }
 \draw[very thick] (L) to[out=20,in=163,looseness=1.2] 
 node[pos=0.2,circle,fill,scale=0.6,label=above right:$h_t(s)$]{} 
 coordinate[pos=0.35] (r3) (R);
\end{scope}
\draw[-latex,shorten >=2pt] (l1) to[out=14,in=220] (r1);
\draw[-latex,shorten >=2pt] (l2) to[out=24,in=140] (r2);
\draw[-latex,shorten >=2pt] (l3) to[out=-12,in=210] (r3);
\end{tikzpicture}

\end{document}

在此处输入图片描述

他们应该用 Ti 来说明Z 你可以做各种很酷的事情,比如计算线和/或面的交点。当然,你可以用一些图形软件做类似的事情,但在我看来,这种方法的优点是你只需要改变一件事就可以进行全局更改。例如,如果你不喜欢虚线的长度,你只需要重新定义样式。最后但并非最不重要的是,我认为这样做更有趣。我当然明白其他人可能不同意我的观点。

附录:将手绘图形转换为“漂亮(更好)”的提案 TiZ 代码。首先以某种格式保存你的手绘图形,这里我将调用文件tmp.png(我刚刚为其拍摄了第一张照片)。然后将其包含在 TiZ 图片并读取一些坐标smooth cycles等等。

\documentclass[tikz,border=3.14mm]{standalone}
\usetikzlibrary{calc}
\begin{document}
\begin{tikzpicture}
\node  (tmp)  {\includegraphics{tmp.png}};
\draw (tmp.south west) grid (tmp.north east);
\draw let \p1=(tmp.south west), \p2=(tmp.north east) in
\pgfextra{\pgfmathsetmacro{\xmin}{int(\x1/1cm)}
\pgfmathsetmacro{\xmax}{int(\x2/1cm)}
\pgfmathsetmacro{\ymin}{int(\y1/1cm)}
\pgfmathsetmacro{\ymax}{int(\y2/1cm)}
\typeout{\xmin,\xmax}}
\foreach \X in {\xmin,...,\xmax} {(\X,\y1) node[anchor=north] {\X}}
\foreach \Y in {\ymin,...,\ymax} {(\x1,\Y) node[anchor=east] {\Y}};
\end{tikzpicture}
\end{document}

在此处输入图片描述

最有可能的是,人们可以编写一个代码来提取轮廓上的一些坐标。我猜,通过机器学习,很快就可以让计算机做到这一点。是的,目前手工做到这一点很痛苦,但也不是特别痛苦。(如果有人已经用带标签的自动网格完成了这件事,我提前道歉,我找不到它,所以我自己很快写了它。在示例中,我发现刻度标签的范围是硬编码的。)

答案2

外部绘图程序(主要用鼠标,而不是手绘)

这些都列在是否有可以生成相应 LaTeX 代码的在线图表图形编辑器?或者对于 PGF/TikZ 来说,所见即所得 (WYSIWYG)?或者有哪些 GUI 应用程序可以帮助生成 TeX 图形?

  • 马查
  • GeoGebra
  • ktikz/qtikz
  • 迪亚
  • Inkscape
  • 提克兹
  • 电路
  • 蒂克
  • 更多杂项工具...

耶茲

yEd 是一款通用的图形编辑器,可以导入各种文件格式,包括手绘图形的图像。它具有将图形导出为 TikZ 代码的功能,然后您可以将其包含在 LaTeX 文档中。虽然它无法完美地重新创建手绘图形,但与在 TikZ 中手动重新创建图形相比,它可以为您节省大量时间和精力。

自由提克

自由提克是一个基于网络的工具,用于将手绘图表转换为 tikz 代码。单击此处运行

信用:https://tex.stackexchange.com/a/670615/250119

答案3

您必须在最初的努力和维护的努力之间进行权衡。@marmot 回答如果您认为将来需要大量修改图表,那么这就是可行的方法。

如果你认为你永远不会改变手工制作的图形,也许一个简单的解决方案导入它们并用tikz使用帮助网格是最快的方法。

一种可能的中间解决方案是跳转到过去并使用基于的解决方案psfrag。请注意,此包不起作用(和无法工作) 采用现代引擎,因此必须使用一些技巧。

psfrag很不错,因为它允许你.eps用 LaTeX 结构(无论什么)替换文件中的字符串。我用它来增强用xcircuit(使用起来非常快,我从未找到更好的东西;尽管我现在正试图转向,因为tkcircuitz我有如此大的电路宝库......)。

我将通过示例向您展示。我用纯文本标签绘制了这个电路;假设它被称为buffer.eps

在此处输入图片描述

然后我为它编写了一个“替换文件”,称之为buffer-psfrag.eps

\mypsf{r50}{\SI{50}{\ohm}}

我有一个通用的psfragdefinitions.tex

%%
%% psfrag and general replacements
%%
\newcommand{\psfscale}{1.2}

\newcommand{\mypsf}[2]{%
  \psfrag{#1}[Bl][Bl][\psfscale]{#2}
}

\mypsf{R}{$R$}
\mypsf{R1}{$R_1$}
\mypsf{R2}{$R_2$}
\mypsf{Rin}{$R_\mathrm{in}$}
\mypsf{Rout}{$R_\mathrm{out}$}
\mypsf{E}{$E$}
\mypsf{I}{$I$}
\mypsf{vo}{$v_o$}
\mypsf{vs}{$v_s$}
\mypsf{vi}{$v_i$}
\mypsf{v+}{$v^+$}
\mypsf{v-}{$v^-$}
\mypsf{L+}{$L^+$}
\mypsf{L-}{$L^-$}

\endinput

然后我使用我编写的一个 python 脚本(附加在这个答案的末尾),该脚本调用旧的latex并执行dvi-> ps->pdf转换,尝试嵌入和子集所有字体(我遇到了问题......):

./epsfragtopdf.py buffer.eps

获得:

在此处输入图片描述

一旦您拥有一组结构良好的包含脚本和 Makefile 来自动化它,它就会非常快;标签经常重复,因此您只需编写一次 psfrag 文件。

我想您可以使用任何允许您手绘、添加标签并保存到 Encapsulated Postscript 的应用程序来执行相同操作。

用 调用的脚本subdir/name.eps将使用在、 然后和 最后psfrag中找到的定义:./psfragdefinitios.texsubdir/psfragdefinitions.texname-psfrag.tex

#!/usr/bin/env python3
#
import sys
import os
import argparse
import tempfile
import subprocess
import shutil
#
latex_pre=r"""\documentclass[12pt]{article}
\usepackage{graphicx,psfrag}
\usepackage[active,tightpage]{preview}
\usepackage{siunitx}
"""
latex_med=r"""\pagestyle {empty}
\begin{document}
\centering\null\vfill
\begin{preview}
"""
latex_post=r"""\end{preview}
\vfill
\end{document}

"""
global_def_fname="psfragdefinitions.tex"
local_def_post="-psfrag"
latex_cmd="TEXINPUTS=$TEXINPUTS:../ latex -interaction nonstopmode go.tex >/dev/null 2>&1"
dvips_cmd="dvips go.dvi >/dev/null 2>&1"
ps2pdf_cmd="ps2pdf -dPDFSETTINGS=/prepress -dEmbedAllFonts=true -dSubsetFonts=true go.ps >/dev/null 2>&1" 
#
# Main
#
parser = argparse.ArgumentParser(description='Convert eps to pdf using psfrag')
parser.add_argument('--force', dest='force', action='store_true', default=False,
                   help='force conversion even if the PDF is newer (default: false)')
parser.add_argument('epsfiles', metavar='eps_file', nargs='+',
                   help='files to be converted')
args = parser.parse_args()
for filepath in args.epsfiles:
    filedir, filename = os.path.split(filepath)
    filebase, fileext = os.path.splitext(filename)
    # print ("dir:", filedir, " base:", filebase, " ext:", fileext)
    if fileext!= ".eps":
        print(filepath, "does not end in .eps, skipped")
        continue
    if not os.path.exists(filepath):
        print(filepath, "does not exists, skipped")
        continue
    targetfilename = filebase + ".pdf"
    targetfilepath = os.path.join(filedir, targetfilename)
    if os.path.exists(targetfilepath) and not args.force and os.path.getmtime(targetfilepath)>os.path.getmtime(filepath): 
        print(targetfilepath, "is newer than", filepath, ", skipped")
        continue
    print("processing", filepath, "to", targetfilepath)
    tmpdir = tempfile.mkdtemp(dir=".")
    # tmpdir = "tmp"
    if not os.path.exists(tmpdir): 
        os.mkdir(tmpdir)
    latexf = open(os.path.join(tmpdir,"go.tex"),"w")
    latexf.write(latex_pre)
    # search the file-definitions in the current dir, in the target dir
    if os.path.exists(global_def_fname):
        latexf.write("\\input{%s}\n" % os.path.join("..",global_def_fname))
        print("including",  global_def_fname)
    if filedir!="" and os.path.exists(os.path.join(filedir, global_def_fname)):
        latexf.write("\\input{%s}\n" % os.path.join("..", os.path.join(filedir, global_def_fname)))
        print("including",  os.path.join(filedir, global_def_fname))
    # search specific file-definition
    specfpath = os.path.join(filedir, filebase + local_def_post + ".tex")
    if os.path.exists(specfpath):
        latexf.write("\\input{%s}\n" % os.path.join("..", specfpath))
        print("including",  specfpath)
    latexf.write(latex_med)
    latexf.write("\\includegraphics{%s}\n" % os.path.join("..",filepath))
    latexf.write(latex_post)
    latexf.close()
    # now we build the figure
    subprocess.check_call(latex_cmd, cwd=tmpdir, shell=True)
    subprocess.check_call(dvips_cmd, cwd=tmpdir, shell=True)
    subprocess.check_call(ps2pdf_cmd,cwd=tmpdir,  shell=True)
    # now we copy the file back where it should be
    shutil.copy(os.path.join(tmpdir,"go.pdf"), targetfilepath)
    shutil.rmtree(tmpdir)

相关内容